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