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