[llvmonly] Share more signatures in the gsharedvt in/out wrappers.
[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
22 #ifdef ENABLE_LLVM
23 #include "mini-llvm-cpp.h"
24 #endif
25
26 void*
27 mono_ldftn (MonoMethod *method)
28 {
29         gpointer addr;
30
31         if (mono_llvm_only) {
32                 // FIXME: No error handling
33
34                 addr = mono_compile_method (method);
35                 g_assert (addr);
36
37                 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
38                         /* The caller doesn't pass it */
39                         g_assert_not_reached ();
40
41                 addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
42                 return addr;
43         }
44
45         addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
46
47         return mono_create_ftnptr (mono_domain_get (), addr);
48 }
49
50 static void*
51 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
52 {
53         MonoError error;
54         MonoMethod *res;
55
56         if (obj == NULL) {
57                 mono_set_pending_exception (mono_get_exception_null_reference ());
58                 return NULL;
59         }
60
61         res = mono_object_get_virtual_method (obj, method);
62
63         if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
64                 MonoGenericContext context = { NULL, NULL };
65
66                 if (res->klass->generic_class)
67                         context.class_inst = res->klass->generic_class->context.class_inst;
68                 else if (res->klass->generic_container)
69                         context.class_inst = res->klass->generic_container->context.class_inst;
70                 context.method_inst = mono_method_get_context (method)->method_inst;
71
72                 res = mono_class_inflate_generic_method_checked (res, &context, &error);
73                 if (!mono_error_ok (&error)) {
74                         mono_error_set_pending_exception (&error);
75                         return NULL;
76                 }
77         }
78
79         /* An rgctx wrapper is added by the trampolines no need to do it here */
80
81         return mono_ldftn (res);
82 }
83
84 void*
85 mono_ldvirtfn (MonoObject *obj, MonoMethod *method) 
86 {
87         return ldvirtfn_internal (obj, method, FALSE);
88 }
89
90 void*
91 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method) 
92 {
93         return ldvirtfn_internal (obj, method, TRUE);
94 }
95
96 void
97 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
98 {
99         if (!array) {
100                 mono_set_pending_exception (mono_get_exception_null_reference ());
101                 return;
102         }
103         if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class)) {
104                 mono_set_pending_exception (mono_get_exception_array_type_mismatch ());
105                 return;
106         }
107 }
108
109 #if !defined(MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS) || defined(MONO_ARCH_EMULATE_LONG_MUL_OVF_OPTS)
110
111 gint64 
112 mono_llmult (gint64 a, gint64 b)
113 {
114         return a * b;
115 }
116
117 guint64  
118 mono_llmult_ovf_un (guint64 a, guint64 b)
119 {
120         guint32 al = a;
121         guint32 ah = a >> 32;
122         guint32 bl = b;
123         guint32 bh = b >> 32; 
124         guint64 res, t1;
125
126         // fixme: this is incredible slow
127
128         if (ah && bh)
129                 goto raise_exception;
130
131         res = (guint64)al * (guint64)bl;
132
133         t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
134
135         if (t1 > 0xffffffff)
136                 goto raise_exception;
137
138         res += ((guint64)t1) << 32; 
139
140         return res;
141
142  raise_exception:
143         mono_set_pending_exception (mono_get_exception_overflow ());
144         return 0;
145 }
146
147 guint64  
148 mono_llmult_ovf (gint64 a, gint64 b) 
149 {
150         guint32 al = a;
151         gint32 ah = a >> 32;
152         guint32 bl = b;
153         gint32 bh = b >> 32; 
154         /*
155         Use Karatsuba algorithm where:
156                 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
157                 where Ah is the "high half" (most significant 32 bits) of a and
158                 where Al is the "low half" (least significant 32 bits) of a and
159                 where  Bh is the "high half" of b and Bl is the "low half" and
160                 where R is the Radix or "size of the half" (in our case 32 bits)
161
162         Note, for the product of two 64 bit numbers to fit into a 64
163         result, ah and/or bh must be 0.  This will save us from doing
164         the AhBh term at all.
165
166         Also note that we refactor so that we don't overflow 64 bits with 
167         intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
168         */
169
170         gint64 res, t1;
171         gint32 sign;
172
173         /* need to work with absoulte values, so find out what the
174            resulting sign will be and convert any negative numbers
175            from two's complement
176         */
177         sign = ah ^ bh;
178         if (ah < 0) {
179                 if (((guint32)ah == 0x80000000) && (al == 0)) {
180                         /* This has no two's complement */
181                         if (b == 0)
182                                 return 0;
183                         else if (b == 1)
184                                 return a;
185                         else
186                                 goto raise_exception;
187                 }
188
189                 /* flip the bits and add 1 */
190                 ah ^= ~0;
191                 if (al ==  0)
192                         ah += 1;
193                 else {
194                         al ^= ~0;
195                         al +=1;
196                 }
197         }
198
199         if (bh < 0) {
200                 if (((guint32)bh == 0x80000000) && (bl == 0)) {
201                         /* This has no two's complement */
202                         if (a == 0)
203                                 return 0;
204                         else if (a == 1)
205                                 return b;
206                         else
207                                 goto raise_exception;
208                 }
209
210                 /* flip the bits and add 1 */
211                 bh ^= ~0;
212                 if (bl ==  0)
213                         bh += 1;
214                 else {
215                         bl ^= ~0;
216                         bl +=1;
217                 }
218         }
219                 
220         /* we overflow for sure if both upper halves are greater 
221            than zero because we would need to shift their 
222            product 64 bits to the left and that will not fit
223            in a 64 bit result */
224         if (ah && bh)
225                 goto raise_exception;
226         if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
227                 goto raise_exception;
228
229         /* do the AlBl term first */
230         t1 = (gint64)al * (gint64)bl;
231
232         res = t1;
233
234         /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
235         t1 += (gint64)(ah - al) * (gint64)(bl - bh);
236         /* check for overflow */
237         t1 <<= 32;
238         if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
239                 goto raise_exception;
240
241         res += t1;
242
243         if (res < 0)
244                 goto raise_exception;
245
246         if (sign < 0)
247                 return -res;
248         else
249                 return res;
250
251  raise_exception:
252         mono_set_pending_exception (mono_get_exception_overflow ());
253         return 0;
254 }
255
256 gint64 
257 mono_lldiv (gint64 a, gint64 b)
258 {
259 #ifdef MONO_ARCH_NEED_DIV_CHECK
260         if (!b) {
261                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
262                 return 0;
263         }
264         else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
265                 mono_set_pending_exception (mono_get_exception_arithmetic ());
266                 return 0;
267         }
268 #endif
269         return a / b;
270 }
271
272 gint64 
273 mono_llrem (gint64 a, gint64 b)
274 {
275 #ifdef MONO_ARCH_NEED_DIV_CHECK
276         if (!b) {
277                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
278                 return 0;
279         }
280         else if (b == -1 && a == (-9223372036854775807LL - 1LL)) {
281                 mono_set_pending_exception (mono_get_exception_arithmetic ());
282                 return 0;
283         }
284 #endif
285         return a % b;
286 }
287
288 guint64 
289 mono_lldiv_un (guint64 a, guint64 b)
290 {
291 #ifdef MONO_ARCH_NEED_DIV_CHECK
292         if (!b) {
293                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
294                 return 0;
295         }
296 #endif
297         return a / b;
298 }
299
300 guint64 
301 mono_llrem_un (guint64 a, guint64 b)
302 {
303 #ifdef MONO_ARCH_NEED_DIV_CHECK
304         if (!b) {
305                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
306                 return 0;
307         }
308 #endif
309         return a % b;
310 }
311
312 #endif
313
314 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
315
316 guint64 
317 mono_lshl (guint64 a, gint32 shamt)
318 {
319         guint64 res;
320
321         res = a << (shamt & 0x7f);
322
323         /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
324
325         return res;
326 }
327
328 guint64 
329 mono_lshr_un (guint64 a, gint32 shamt)
330 {
331         guint64 res;
332
333         res = a >> (shamt & 0x7f);
334
335         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
336
337         return res;
338 }
339
340 gint64 
341 mono_lshr (gint64 a, gint32 shamt)
342 {
343         gint64 res;
344
345         res = a >> (shamt & 0x7f);
346
347         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
348
349         return res;
350 }
351
352 #endif
353
354 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
355
356 gint32
357 mono_idiv (gint32 a, gint32 b)
358 {
359 #ifdef MONO_ARCH_NEED_DIV_CHECK
360         if (!b) {
361                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
362                 return 0;
363         }
364         else if (b == -1 && a == (0x80000000)) {
365                 mono_set_pending_exception (mono_get_exception_overflow ());
366                 return 0;
367         }
368 #endif
369         return a / b;
370 }
371
372 guint32
373 mono_idiv_un (guint32 a, guint32 b)
374 {
375 #ifdef MONO_ARCH_NEED_DIV_CHECK
376         if (!b) {
377                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
378                 return 0;
379         }
380 #endif
381         return a / b;
382 }
383
384 gint32
385 mono_irem (gint32 a, gint32 b)
386 {
387 #ifdef MONO_ARCH_NEED_DIV_CHECK
388         if (!b) {
389                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
390                 return 0;
391         }
392         else if (b == -1 && a == (0x80000000)) {
393                 mono_set_pending_exception (mono_get_exception_overflow ());
394                 return 0;
395         }
396 #endif
397         return a % b;
398 }
399
400 guint32
401 mono_irem_un (guint32 a, guint32 b)
402 {
403 #ifdef MONO_ARCH_NEED_DIV_CHECK
404         if (!b) {
405                 mono_set_pending_exception (mono_get_exception_divide_by_zero ());
406                 return 0;
407         }
408 #endif
409         return a % b;
410 }
411
412 #endif
413
414 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
415
416 gint32
417 mono_imul (gint32 a, gint32 b)
418 {
419         return a * b;
420 }
421
422 gint32
423 mono_imul_ovf (gint32 a, gint32 b)
424 {
425         gint64 res;
426
427         res = (gint64)a * (gint64)b;
428
429         if ((res > 0x7fffffffL) || (res < -2147483648LL)) {
430                 mono_set_pending_exception (mono_get_exception_overflow ());
431                 return 0;
432         }
433
434         return res;
435 }
436
437 gint32
438 mono_imul_ovf_un (guint32 a, guint32 b)
439 {
440         guint64 res;
441
442         res = (guint64)a * (guint64)b;
443
444         if (res >> 32) {
445                 mono_set_pending_exception (mono_get_exception_overflow ());
446                 return 0;
447         }
448
449         return res;
450 }
451 #endif
452
453 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
454 double
455 mono_fdiv (double a, double b)
456 {
457         return a / b;
458 }
459 #endif
460
461 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
462
463 double
464 mono_fsub (double a, double b)
465 {
466         return a - b;
467 }
468
469 double
470 mono_fadd (double a, double b)
471 {
472         return a + b;
473 }
474
475 double
476 mono_fmul (double a, double b)
477 {
478         return a * b;
479 }
480
481 double
482 mono_fneg (double a)
483 {
484         return -a;
485 }
486
487 double
488 mono_fconv_r4 (double a)
489 {
490         return (float)a;
491 }
492
493 double
494 mono_conv_to_r8 (int a)
495 {
496         return (double)a;
497 }
498
499 double
500 mono_conv_to_r4 (int a)
501 {
502         return (double)(float)a;
503 }
504
505 gint8
506 mono_fconv_i1 (double a)
507 {
508         return (gint8)a;
509 }
510
511 gint16
512 mono_fconv_i2 (double a)
513 {
514         return (gint16)a;
515 }
516
517 gint32
518 mono_fconv_i4 (double a)
519 {
520         return (gint32)a;
521 }
522
523 guint8
524 mono_fconv_u1 (double a)
525 {
526         return (guint8)a;
527 }
528
529 guint16
530 mono_fconv_u2 (double a)
531 {
532         return (guint16)a;
533 }
534
535 gboolean
536 mono_fcmp_eq (double a, double b)
537 {
538         return a == b;
539 }
540
541 gboolean
542 mono_fcmp_ge (double a, double b)
543 {
544         return a >= b;
545 }
546
547 gboolean
548 mono_fcmp_gt (double a, double b)
549 {
550         return a > b;
551 }
552
553 gboolean
554 mono_fcmp_le (double a, double b)
555 {
556         return a <= b;
557 }
558
559 gboolean
560 mono_fcmp_lt (double a, double b)
561 {
562         return a < b;
563 }
564
565 gboolean
566 mono_fcmp_ne_un (double a, double b)
567 {
568         return isunordered (a, b) || a != b;
569 }
570
571 gboolean
572 mono_fcmp_ge_un (double a, double b)
573 {
574         return isunordered (a, b) || a >= b;
575 }
576
577 gboolean
578 mono_fcmp_gt_un (double a, double b)
579 {
580         return isunordered (a, b) || a > b;
581 }
582
583 gboolean
584 mono_fcmp_le_un (double a, double b)
585 {
586         return isunordered (a, b) || a <= b;
587 }
588
589 gboolean
590 mono_fcmp_lt_un (double a, double b)
591 {
592         return isunordered (a, b) || a < b;
593 }
594
595 gboolean
596 mono_fceq (double a, double b)
597 {
598         return a == b;
599 }
600
601 gboolean
602 mono_fcgt (double a, double b)
603 {
604         return a > b;
605 }
606
607 gboolean
608 mono_fcgt_un (double a, double b)
609 {
610         return isunordered (a, b) || a > b;
611 }
612
613 gboolean
614 mono_fclt (double a, double b)
615 {
616         return a < b;
617 }
618
619 gboolean
620 mono_fclt_un (double a, double b)
621 {
622         return isunordered (a, b) || a < b;
623 }
624
625 gboolean
626 mono_isfinite (double a)
627 {
628 #ifdef HAVE_ISFINITE
629         return isfinite (a);
630 #else
631         g_assert_not_reached ();
632         return TRUE;
633 #endif
634 }
635
636 double
637 mono_fload_r4 (float *ptr)
638 {
639         return *ptr;
640 }
641
642 void
643 mono_fstore_r4 (double val, float *ptr)
644 {
645         *ptr = (float)val;
646 }
647
648 /* returns the integer bitpattern that is passed in the regs or stack */
649 guint32
650 mono_fload_r4_arg (double val)
651 {
652         float v = (float)val;
653         return *(guint32*)&v;
654 }
655
656 #endif
657
658 MonoArray *
659 mono_array_new_va (MonoMethod *cm, ...)
660 {
661         MonoDomain *domain = mono_domain_get ();
662         va_list ap;
663         uintptr_t *lengths;
664         intptr_t *lower_bounds;
665         int pcount;
666         int rank;
667         int i, d;
668
669         pcount = mono_method_signature (cm)->param_count;
670         rank = cm->klass->rank;
671
672         va_start (ap, cm);
673         
674         lengths = (uintptr_t *)alloca (sizeof (uintptr_t) * pcount);
675         for (i = 0; i < pcount; ++i)
676                 lengths [i] = d = va_arg(ap, int);
677
678         if (rank == pcount) {
679                 /* Only lengths provided. */
680                 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
681                         lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
682                         memset (lower_bounds, 0, sizeof (intptr_t) * rank);
683                 } else {
684                         lower_bounds = NULL;
685                 }
686         } else {
687                 g_assert (pcount == (rank * 2));
688                 /* lower bounds are first. */
689                 lower_bounds = (intptr_t*)lengths;
690                 lengths += rank;
691         }
692         va_end(ap);
693
694         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
695 }
696
697 /* Specialized version of mono_array_new_va () which avoids varargs */
698 MonoArray *
699 mono_array_new_1 (MonoMethod *cm, guint32 length)
700 {
701         MonoDomain *domain = mono_domain_get ();
702         uintptr_t lengths [1];
703         intptr_t *lower_bounds;
704         int pcount;
705         int rank;
706
707         pcount = mono_method_signature (cm)->param_count;
708         rank = cm->klass->rank;
709
710         lengths [0] = length;
711
712         g_assert (rank == pcount);
713
714         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
715                 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
716                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
717         } else {
718                 lower_bounds = NULL;
719         }
720
721         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
722 }
723
724 MonoArray *
725 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
726 {
727         MonoDomain *domain = mono_domain_get ();
728         uintptr_t lengths [2];
729         intptr_t *lower_bounds;
730         int pcount;
731         int rank;
732
733         pcount = mono_method_signature (cm)->param_count;
734         rank = cm->klass->rank;
735
736         lengths [0] = length1;
737         lengths [1] = length2;
738
739         g_assert (rank == pcount);
740
741         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
742                 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
743                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
744         } else {
745                 lower_bounds = NULL;
746         }
747
748         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
749 }
750
751 MonoArray *
752 mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3)
753 {
754         MonoDomain *domain = mono_domain_get ();
755         uintptr_t lengths [3];
756         intptr_t *lower_bounds;
757         int pcount;
758         int rank;
759
760         pcount = mono_method_signature (cm)->param_count;
761         rank = cm->klass->rank;
762
763         lengths [0] = length1;
764         lengths [1] = length2;
765         lengths [2] = length3;
766
767         g_assert (rank == pcount);
768
769         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
770                 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
771                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
772         } else {
773                 lower_bounds = NULL;
774         }
775
776         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
777 }
778
779 MonoArray *
780 mono_array_new_4 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3, guint32 length4)
781 {
782         MonoDomain *domain = mono_domain_get ();
783         uintptr_t lengths [4];
784         intptr_t *lower_bounds;
785         int pcount;
786         int rank;
787
788         pcount = mono_method_signature (cm)->param_count;
789         rank = cm->klass->rank;
790
791         lengths [0] = length1;
792         lengths [1] = length2;
793         lengths [2] = length3;
794         lengths [3] = length4;
795
796         g_assert (rank == pcount);
797
798         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
799                 lower_bounds = (intptr_t *)alloca (sizeof (intptr_t) * rank);
800                 memset (lower_bounds, 0, sizeof (intptr_t) * rank);
801         } else {
802                 lower_bounds = NULL;
803         }
804
805         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
806 }
807
808 gpointer
809 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
810 {
811         MonoVTable *vtable;
812         gpointer addr;
813         
814         //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
815
816         mono_class_init (field->parent);
817
818         vtable = mono_class_vtable_full (domain, field->parent, TRUE);
819         if (!vtable->initialized)
820                 mono_runtime_class_init (vtable);
821
822         //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
823
824         if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
825                 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
826         else
827                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
828         
829         return addr;
830 }
831
832 gpointer
833 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
834 {
835         MonoError error;
836         MonoClass *handle_class;
837         gpointer res;
838
839         res = mono_ldtoken_checked (image, token, &handle_class, context, &error);
840         if (!mono_error_ok (&error)) {
841                 mono_error_set_pending_exception (&error);
842                 return NULL;
843         }
844         mono_class_init (handle_class);
845
846         return res;
847 }
848
849 gpointer
850 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
851 {
852         MonoMethodSignature *sig = mono_method_signature (method);
853         MonoGenericContext *generic_context;
854
855         if (sig->is_inflated) {
856                 generic_context = mono_method_get_context (method);
857         } else {
858                 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
859                 g_assert (generic_container);
860                 generic_context = &generic_container->context;
861         }
862
863         return mono_ldtoken_wrapper (image, token, generic_context);
864 }
865
866 guint64
867 mono_fconv_u8 (double v)
868 {
869         return (guint64)v;
870 }
871
872 guint64
873 mono_rconv_u8 (float v)
874 {
875         return (guint64)v;
876 }
877
878 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
879 gint64
880 mono_fconv_i8 (double v)
881 {
882         return (gint64)v;
883 }
884 #endif
885
886 guint32
887 mono_fconv_u4 (double v)
888 {
889         /* MS.NET behaves like this for some reason */
890 #ifdef HAVE_ISINF
891         if (isinf (v) || isnan (v))
892                 return 0;
893 #endif
894
895         return (guint32)v;
896 }
897
898 #ifndef HAVE_TRUNC
899 /* Solaris doesn't have trunc */
900 #ifdef HAVE_AINTL
901 extern long double aintl (long double);
902 #define trunc aintl
903 #else
904 /* FIXME: This means we will never throw overflow exceptions */
905 #define trunc(v) res
906 #endif
907 #endif /* HAVE_TRUNC */
908
909 gint64
910 mono_fconv_ovf_i8 (double v)
911 {
912         gint64 res;
913
914         res = (gint64)v;
915
916         if (isnan(v) || trunc (v) != res) {
917                 mono_set_pending_exception (mono_get_exception_overflow ());
918                 return 0;
919         }
920         return res;
921 }
922
923 guint64
924 mono_fconv_ovf_u8 (double v)
925 {
926         guint64 res;
927
928 /*
929  * The soft-float implementation of some ARM devices have a buggy guin64 to double
930  * conversion that it looses precision even when the integer if fully representable
931  * as a double.
932  * 
933  * This was found with 4294967295ull, converting to double and back looses one bit of precision.
934  * 
935  * To work around this issue we test for value boundaries instead. 
936  */
937 #if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
938         if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
939                 mono_set_pending_exception (mono_get_exception_overflow ());
940                 return 0;
941         }
942         res = (guint64)v;
943 #else
944         res = (guint64)v;
945         if (isnan(v) || trunc (v) != res) {
946                 mono_set_pending_exception (mono_get_exception_overflow ());
947                 return 0;
948         }
949 #endif
950         return res;
951 }
952
953 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
954 gint64
955 mono_rconv_i8 (float v)
956 {
957         return (gint64)v;
958 }
959 #endif
960
961 gint64
962 mono_rconv_ovf_i8 (float v)
963 {
964         gint64 res;
965
966         res = (gint64)v;
967
968         if (isnan(v) || trunc (v) != res) {
969                 mono_set_pending_exception (mono_get_exception_overflow ());
970                 return 0;
971         }
972         return res;
973 }
974
975 guint64
976 mono_rconv_ovf_u8 (float v)
977 {
978         guint64 res;
979
980         res = (guint64)v;
981         if (isnan(v) || trunc (v) != res) {
982                 mono_set_pending_exception (mono_get_exception_overflow ());
983                 return 0;
984         }
985         return res;
986 }
987
988 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
989 double
990 mono_lconv_to_r8 (gint64 a)
991 {
992         return (double)a;
993 }
994 #endif
995
996 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
997 float
998 mono_lconv_to_r4 (gint64 a)
999 {
1000         return (float)a;
1001 }
1002 #endif
1003
1004 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
1005 double
1006 mono_conv_to_r8_un (guint32 a)
1007 {
1008         return (double)a;
1009 }
1010 #endif
1011
1012 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
1013 double
1014 mono_lconv_to_r8_un (guint64 a)
1015 {
1016         return (double)a;
1017 }
1018 #endif
1019
1020 #if defined(__native_client_codegen__) || defined(__native_client__)
1021 /* When we cross-compile to Native Client we can't directly embed calls */
1022 /* to the math library on the host. This will use the fmod on the target*/
1023 double
1024 mono_fmod(double a, double b)
1025 {
1026         return fmod(a, b);
1027 }
1028 #endif
1029
1030 gpointer
1031 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
1032 {
1033         MonoMethod *vmethod;
1034         gpointer addr;
1035         MonoGenericContext *context = mono_method_get_context (method);
1036
1037         mono_jit_stats.generic_virtual_invocations++;
1038
1039         if (obj == NULL) {
1040                 mono_set_pending_exception (mono_get_exception_null_reference ());
1041                 return NULL;
1042         }
1043         vmethod = mono_object_get_virtual_method (obj, method);
1044         g_assert (!vmethod->klass->generic_container);
1045         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
1046         g_assert (!context->method_inst || !context->method_inst->is_open);
1047
1048         addr = mono_compile_method (vmethod);
1049
1050         addr = mini_add_method_trampoline (vmethod, addr, mono_method_needs_static_rgctx_invoke (vmethod, FALSE), FALSE);
1051
1052         /* Since this is a virtual call, have to unbox vtypes */
1053         if (obj->vtable->klass->valuetype)
1054                 *this_arg = mono_object_unbox (obj);
1055         else
1056                 *this_arg = obj;
1057
1058         return addr;
1059 }
1060
1061 MonoString*
1062 mono_helper_ldstr (MonoImage *image, guint32 idx)
1063 {
1064         return mono_ldstr (mono_domain_get (), image, idx);
1065 }
1066
1067 MonoString*
1068 mono_helper_ldstr_mscorlib (guint32 idx)
1069 {
1070         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
1071 }
1072
1073 MonoObject*
1074 mono_helper_newobj_mscorlib (guint32 idx)
1075 {
1076         MonoError error;
1077         MonoClass *klass = mono_class_get_checked (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx, &error);
1078
1079         if (!mono_error_ok (&error)) {
1080                 mono_error_set_pending_exception (&error);
1081                 return NULL;
1082         }
1083
1084         return mono_object_new (mono_domain_get (), klass);
1085 }
1086
1087 /*
1088  * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
1089  * in generated code. So instead we emit a call to this function and place a gdb
1090  * breakpoint here.
1091  */
1092 void
1093 mono_break (void)
1094 {
1095 }
1096
1097 MonoException *
1098 mono_create_corlib_exception_0 (guint32 token)
1099 {
1100         return mono_exception_from_token (mono_defaults.corlib, token);
1101 }
1102
1103 MonoException *
1104 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
1105 {
1106         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
1107 }
1108
1109 MonoException *
1110 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
1111 {
1112         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
1113 }
1114
1115 MonoObject*
1116 mono_object_castclass_unbox (MonoObject *obj, MonoClass *klass)
1117 {
1118         MonoJitTlsData *jit_tls = NULL;
1119         MonoClass *oklass;
1120
1121         if (mini_get_debug_options ()->better_cast_details) {
1122                 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1123                 jit_tls->class_cast_from = NULL;
1124         }
1125
1126         if (!obj)
1127                 return NULL;
1128
1129         oklass = obj->vtable->klass;
1130         if ((klass->enumtype && oklass == klass->element_class) || (oklass->enumtype && klass == oklass->element_class))
1131                 return obj;
1132         if (mono_object_isinst (obj, klass))
1133                 return obj;
1134
1135         if (mini_get_debug_options ()->better_cast_details) {
1136                 jit_tls->class_cast_from = oklass;
1137                 jit_tls->class_cast_to = klass;
1138         }
1139
1140         mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1141                                         "System", "InvalidCastException"));
1142
1143         return NULL;
1144 }
1145
1146 MonoObject*
1147 mono_object_castclass_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1148 {
1149         MonoJitTlsData *jit_tls = NULL;
1150         gpointer cached_vtable, obj_vtable;
1151
1152         if (mini_get_debug_options ()->better_cast_details) {
1153                 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1154                 jit_tls->class_cast_from = NULL;
1155         }
1156
1157         if (!obj)
1158                 return NULL;
1159
1160         cached_vtable = *cache;
1161         obj_vtable = obj->vtable;
1162
1163         if (cached_vtable == obj_vtable)
1164                 return obj;
1165
1166         if (mono_object_isinst (obj, klass)) {
1167                 *cache = obj_vtable;
1168                 return obj;
1169         }
1170
1171         if (mini_get_debug_options ()->better_cast_details) {
1172                 jit_tls->class_cast_from = obj->vtable->klass;
1173                 jit_tls->class_cast_to = klass;
1174         }
1175
1176         mono_set_pending_exception (mono_exception_from_name (mono_defaults.corlib,
1177                                         "System", "InvalidCastException"));
1178
1179         return NULL;
1180 }
1181
1182 MonoObject*
1183 mono_object_isinst_with_cache (MonoObject *obj, MonoClass *klass, gpointer *cache)
1184 {
1185         size_t cached_vtable, obj_vtable;
1186
1187         if (!obj)
1188                 return NULL;
1189
1190         cached_vtable = (size_t)*cache;
1191         obj_vtable = (size_t)obj->vtable;
1192
1193         if ((cached_vtable & ~0x1) == obj_vtable) {
1194                 return (cached_vtable & 0x1) ? NULL : obj;
1195         }
1196
1197         if (mono_object_isinst (obj, klass)) {
1198                 *cache = (gpointer)obj_vtable;
1199                 return obj;
1200         } else {
1201                 /*negative cache*/
1202                 *cache = (gpointer)(obj_vtable | 0x1);
1203                 return NULL;
1204         }
1205 }
1206
1207 gpointer
1208 mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func)
1209 {
1210         MonoMarshalSpec **mspecs;
1211         MonoMethodPInvoke piinfo;
1212         MonoMethod *m;
1213
1214         mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
1215         memset (&piinfo, 0, sizeof (piinfo));
1216
1217         m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func);
1218
1219         return mono_compile_method (m);
1220 }
1221
1222 static MonoMethod*
1223 constrained_gsharedvt_call_setup (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gpointer *this_arg)
1224 {
1225         MonoMethod *m;
1226         int vt_slot, iface_offset;
1227
1228         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1229                 MonoObject *this_obj;
1230
1231                 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1232                 this_obj = *(MonoObject**)mp;
1233                 g_assert (this_obj);
1234
1235                 klass = this_obj->vtable->klass;
1236         }
1237
1238         if (mono_method_signature (cmethod)->pinvoke) {
1239                 /* Object.GetType () */
1240                 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1241         } else {
1242                 /* Lookup the virtual method */
1243                 mono_class_setup_vtable (klass);
1244                 g_assert (klass->vtable);
1245                 vt_slot = mono_method_get_vtable_slot (cmethod);
1246                 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1247                         iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1248                         g_assert (iface_offset != -1);
1249                         vt_slot += iface_offset;
1250                 }
1251                 m = klass->vtable [vt_slot];
1252                 if (cmethod->is_inflated)
1253                         m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1254         }
1255
1256         if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1257                 /*
1258                  * Calling a non-vtype method with a vtype receiver, has to box.
1259                  */
1260                 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1261         else if (klass->valuetype)
1262                 /*
1263                  * Calling a vtype method with a vtype receiver
1264                  */
1265                 *this_arg = mp;
1266         else
1267                 /*
1268                  * Calling a non-vtype method
1269                  */
1270                 *this_arg = *(gpointer*)mp;
1271         return m;
1272 }
1273
1274 /*
1275  * mono_gsharedvt_constrained_call:
1276  *
1277  *   Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1278  * the arguments to the method in the format used by mono_runtime_invoke ().
1279  */
1280 MonoObject*
1281 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1282 {
1283         MonoMethod *m;
1284         gpointer this_arg;
1285         gpointer new_args [16];
1286
1287         m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg);
1288         if (!m)
1289                 return NULL;
1290         if (args && deref_arg) {
1291                 new_args [0] = *(gpointer*)args [0];
1292                 args = new_args;
1293         }
1294         if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1295                 /* Object.GetType () */
1296                 args = new_args;
1297                 args [0] = this_arg;
1298                 this_arg = NULL;
1299         }
1300         return mono_runtime_invoke (m, this_arg, args, NULL);
1301 }
1302
1303 void
1304 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1305 {
1306         if (klass->valuetype)
1307                 mono_value_copy (dest, src, klass);
1308         else
1309         mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1310 }
1311
1312 void
1313 mono_generic_class_init (MonoVTable *vtable)
1314 {
1315         mono_runtime_class_init (vtable);
1316 }
1317
1318 gpointer
1319 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1320 {
1321         return mono_class_fill_runtime_generic_context (vtable, index);
1322 }
1323
1324 gpointer
1325 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1326 {
1327         return mono_method_fill_runtime_generic_context (mrgctx, index);
1328 }
1329
1330 /*
1331  * resolve_iface_call:
1332  *
1333  *   Return the executable code for the iface method IMT_METHOD called on THIS.
1334  * This function is called on a slowpath, so it doesn't need to be fast.
1335  * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1336  * out parameter.
1337  */
1338 static gpointer
1339 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
1340 {
1341         MonoVTable *vt;
1342         gpointer *imt, *vtable_slot;
1343         MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1344         gpointer addr, compiled_method, aot_addr;
1345         gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1346
1347         if (!this_obj)
1348                 /* The caller will handle it */
1349                 return NULL;
1350
1351         vt = this_obj->vtable;
1352         imt = (gpointer*)vt - MONO_IMT_SIZE;
1353
1354         vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1355
1356         // FIXME: This can throw exceptions
1357         addr = compiled_method = mono_compile_method (impl_method);
1358         g_assert (addr);
1359
1360         if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1361                 generic_virtual = imt_method;
1362
1363         if (generic_virtual || variant_iface) {
1364                 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1365                         need_unbox_tramp = TRUE;
1366         } else {
1367                 if (impl_method->klass->valuetype)
1368                         need_unbox_tramp = TRUE;
1369         }
1370
1371         addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1372
1373         if (generic_virtual || variant_iface) {
1374                 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1375
1376                 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1377                                                                                                         vt, imt + imt_slot,
1378                                                                                                         target, addr);
1379         }
1380
1381         return addr;
1382 }
1383
1384 gpointer
1385 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1386 {
1387         return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
1388 }
1389
1390 static gboolean
1391 is_generic_method_definition (MonoMethod *m)
1392 {
1393         MonoGenericContext *context;
1394         if (m->is_generic)
1395                 return TRUE;
1396         if (!m->is_inflated)
1397                 return FALSE;
1398
1399         context = mono_method_get_context (m);
1400         if (!context->method_inst)
1401                 return FALSE;
1402         if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1403                 return TRUE;
1404         return FALSE;
1405 }
1406
1407 /*
1408  * resolve_vcall:
1409  *
1410  *   Return the executable code for calling vt->vtable [slot].
1411  * This function is called on a slowpath, so it doesn't need to be fast.
1412  * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1413  * out parameter.
1414  */
1415 static gpointer
1416 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
1417 {
1418         MonoMethod *m, *generic_virtual = NULL;
1419         gpointer addr, compiled_method;
1420         gboolean need_unbox_tramp = FALSE;
1421
1422         /* Same as in common_call_trampoline () */
1423
1424         /* Avoid loading metadata or creating a generic vtable if possible */
1425         addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1426         if (addr && !vt->klass->valuetype)
1427                 return mono_create_ftnptr (mono_domain_get (), addr);
1428
1429         m = mono_class_get_vtable_entry (vt->klass, slot);
1430
1431         if (is_generic_method_definition (m)) {
1432                 MonoError error;
1433                 MonoGenericContext context = { NULL, NULL };
1434                 MonoMethod *declaring;
1435
1436                 if (m->is_inflated)
1437                         declaring = mono_method_get_declaring_generic_method (m);
1438                 else
1439                         declaring = m;
1440
1441                 if (m->klass->generic_class)
1442                         context.class_inst = m->klass->generic_class->context.class_inst;
1443                 else
1444                         g_assert (!m->klass->generic_container);
1445
1446                 generic_virtual = imt_method;
1447                 g_assert (generic_virtual);
1448                 g_assert (generic_virtual->is_inflated);
1449                 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1450
1451                 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1452                 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1453         }
1454
1455         if (generic_virtual) {
1456                 if (vt->klass->valuetype)
1457                         need_unbox_tramp = TRUE;
1458         } else {
1459                 if (m->klass->valuetype)
1460                         need_unbox_tramp = TRUE;
1461         }
1462
1463         // FIXME: This can throw exceptions
1464         addr = compiled_method = mono_compile_method (m);
1465         g_assert (addr);
1466
1467         addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, out_arg);
1468
1469         if (gsharedvt) {
1470                 /*
1471                  * The caller uses the gsharedvt calling convention, have to add an out wrapper.
1472                  */
1473                 g_assert (out_arg);
1474
1475                 gpointer out_wrapper = mini_get_gsharedvt_wrapper (FALSE, NULL, mono_method_signature (imt_method), NULL, -1, FALSE);
1476                 MonoFtnDesc *out_wrapper_arg = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, *out_arg);
1477
1478                 addr = out_wrapper;
1479                 *out_arg = out_wrapper_arg;
1480         }
1481
1482         if (!gsharedvt && generic_virtual) {
1483                 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1484                 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1485
1486                 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1487                                                                                                         vt, vt->vtable + slot,
1488                                                                                                         generic_virtual, ftndesc);
1489         }
1490
1491         return addr;
1492 }
1493
1494 gpointer
1495 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1496 {
1497         g_assert (this_obj);
1498
1499         return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1500 }
1501
1502 /*
1503  * mono_resolve_generic_virtual_call:
1504  *
1505  *   Resolve a generic virtual call.
1506  * This function is called on a slowpath, so it doesn't need to be fast.
1507  */
1508 MonoFtnDesc*
1509 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1510 {
1511         MonoMethod *m;
1512         gpointer addr, compiled_method;
1513         gboolean need_unbox_tramp = FALSE;
1514         MonoError error;
1515         MonoGenericContext context = { NULL, NULL };
1516         MonoMethod *declaring;
1517         gpointer arg = NULL;
1518
1519         m = mono_class_get_vtable_entry (vt->klass, slot);
1520
1521         g_assert (is_generic_method_definition (m));
1522
1523         if (m->is_inflated)
1524                 declaring = mono_method_get_declaring_generic_method (m);
1525         else
1526                 declaring = m;
1527
1528         if (m->klass->generic_class)
1529                 context.class_inst = m->klass->generic_class->context.class_inst;
1530         else
1531                 g_assert (!m->klass->generic_container);
1532
1533         g_assert (generic_virtual->is_inflated);
1534         context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1535
1536         m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1537         g_assert (mono_error_ok (&error));
1538
1539         if (vt->klass->valuetype)
1540                 need_unbox_tramp = TRUE;
1541
1542         // FIXME: This can throw exceptions
1543         addr = compiled_method = mono_compile_method (m);
1544         g_assert (addr);
1545
1546         addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1547
1548         /*
1549          * This wastes memory but the memory usage is bounded since
1550          * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1551          * this vtable slot so we are not called any more for this instantiation.
1552          */
1553         MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1554
1555         mono_method_add_generic_virtual_invocation (mono_domain_get (),
1556                                                                                                 vt, vt->vtable + slot,
1557                                                                                                 generic_virtual, ftndesc);
1558         return ftndesc;
1559 }
1560
1561 /*
1562  * mono_resolve_generic_virtual_call:
1563  *
1564  *   Resolve a generic virtual call on interfaces.
1565  * This function is called on a slowpath, so it doesn't need to be fast.
1566  */
1567 MonoFtnDesc*
1568 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1569 {
1570         MonoMethod *m, *variant_iface;
1571         gpointer addr, aot_addr, compiled_method;
1572         gboolean need_unbox_tramp = FALSE;
1573         gboolean need_rgctx_tramp;
1574         gpointer arg = NULL;
1575         gpointer *imt;
1576
1577         imt = (gpointer*)vt - MONO_IMT_SIZE;
1578
1579         mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1580         g_assert (!variant_iface);
1581
1582         if (vt->klass->valuetype)
1583                 need_unbox_tramp = TRUE;
1584
1585         // FIXME: This can throw exceptions
1586         addr = compiled_method = mono_compile_method (m);
1587         g_assert (addr);
1588
1589         addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1590
1591         /*
1592          * This wastes memory but the memory usage is bounded since
1593          * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1594          * this vtable slot so we are not called any more for this instantiation.
1595          */
1596         MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1597
1598         mono_method_add_generic_virtual_invocation (mono_domain_get (),
1599                                                                                                 vt, imt + imt_slot,
1600                                                                                                 generic_virtual, ftndesc);
1601         return ftndesc;
1602 }
1603
1604 /*
1605  * mono_init_vtable_slot:
1606  *
1607  *   Initialize slot SLOT of VTABLE.
1608  * Return the contents of the vtable slot.
1609  */
1610 gpointer
1611 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1612 {
1613         gpointer arg = NULL;
1614         gpointer addr;
1615         gpointer *ftnptr;
1616
1617         addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1618         ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1619         ftnptr [0] = addr;
1620         ftnptr [1] = arg;
1621         mono_memory_barrier ();
1622
1623         vtable->vtable [slot] = ftnptr;
1624
1625         return ftnptr;
1626 }
1627
1628 /*
1629  * mono_init_delegate:
1630  *
1631  *   Initialize a MonoDelegate object.
1632  * Similar to mono_delegate_ctor ().
1633  */
1634 void
1635 mono_init_delegate (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1636 {
1637         MONO_OBJECT_SETREF (del, target, target);
1638         del->method = method;
1639         del->method_ptr = mono_compile_method (method);
1640
1641         del->method_ptr = mini_add_method_wrappers_llvmonly (method, del->method_ptr, FALSE, FALSE, &del->rgctx);
1642         if (!del->rgctx) {
1643                 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
1644                         del->rgctx = mini_method_get_rgctx (method);
1645         }
1646 }
1647
1648 void
1649 mono_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1650 {
1651         g_assert (target);
1652
1653         method = mono_object_get_virtual_method (target, method);
1654
1655         MONO_OBJECT_SETREF (del, target, target);
1656         del->method = method;
1657         del->method_ptr = mono_compile_method (method);
1658
1659         del->method_ptr = mini_add_method_wrappers_llvmonly (method, del->method_ptr, FALSE, FALSE, &del->rgctx);
1660         if (!del->rgctx) {
1661                 if (mono_method_needs_static_rgctx_invoke (method, FALSE))
1662                         del->rgctx = mini_method_get_rgctx (method);
1663         }
1664 }
1665
1666 MonoObject*
1667 mono_get_assembly_object (MonoImage *image)
1668 {
1669         return (MonoObject*)mono_assembly_get_object (mono_domain_get (), image->assembly);
1670 }
1671
1672 double
1673 mono_ckfinite (double d)
1674 {
1675         if (isinf (d) || isnan (d))
1676                 mono_set_pending_exception (mono_get_exception_arithmetic ());
1677         return d;
1678 }