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