Merge pull request #2522 from ludovic-henry/test-socketresponder-task
[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, MonoError *error)
1270 {
1271         MonoMethod *m;
1272         int vt_slot, iface_offset;
1273
1274         mono_error_init (error);
1275
1276         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1277                 MonoObject *this_obj;
1278
1279                 /* Have to use the receiver's type instead of klass, the receiver is a ref type */
1280                 this_obj = *(MonoObject**)mp;
1281                 g_assert (this_obj);
1282
1283                 klass = this_obj->vtable->klass;
1284         }
1285
1286         if (mono_method_signature (cmethod)->pinvoke) {
1287                 /* Object.GetType () */
1288                 m = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
1289         } else {
1290                 /* Lookup the virtual method */
1291                 mono_class_setup_vtable (klass);
1292                 g_assert (klass->vtable);
1293                 vt_slot = mono_method_get_vtable_slot (cmethod);
1294                 if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1295                         iface_offset = mono_class_interface_offset (klass, cmethod->klass);
1296                         g_assert (iface_offset != -1);
1297                         vt_slot += iface_offset;
1298                 }
1299                 m = klass->vtable [vt_slot];
1300                 if (cmethod->is_inflated)
1301                         m = mono_class_inflate_generic_method (m, mono_method_get_context (cmethod));
1302         }
1303
1304         if (klass->valuetype && (m->klass == mono_defaults.object_class || m->klass == mono_defaults.enum_class->parent || m->klass == mono_defaults.enum_class))
1305                 /*
1306                  * Calling a non-vtype method with a vtype receiver, has to box.
1307                  */
1308                 *this_arg = mono_value_box (mono_domain_get (), klass, mp);
1309         else if (klass->valuetype)
1310                 /*
1311                  * Calling a vtype method with a vtype receiver
1312                  */
1313                 *this_arg = mp;
1314         else
1315                 /*
1316                  * Calling a non-vtype method
1317                  */
1318                 *this_arg = *(gpointer*)mp;
1319         return m;
1320 }
1321
1322 /*
1323  * mono_gsharedvt_constrained_call:
1324  *
1325  *   Make a call to CMETHOD using the receiver MP, which is assumed to be of type KLASS. ARGS contains
1326  * the arguments to the method in the format used by mono_runtime_invoke ().
1327  */
1328 MonoObject*
1329 mono_gsharedvt_constrained_call (gpointer mp, MonoMethod *cmethod, MonoClass *klass, gboolean deref_arg, gpointer *args)
1330 {
1331         MonoError error;
1332         MonoMethod *m;
1333         gpointer this_arg;
1334         gpointer new_args [16];
1335
1336         m = constrained_gsharedvt_call_setup (mp, cmethod, klass, &this_arg, &error);
1337         if (!mono_error_ok (&error)) {
1338                 mono_error_set_pending_exception (&error);
1339                 return NULL;
1340         }
1341
1342         if (!m)
1343                 return NULL;
1344         if (args && deref_arg) {
1345                 new_args [0] = *(gpointer*)args [0];
1346                 args = new_args;
1347         }
1348         if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
1349                 /* Object.GetType () */
1350                 args = new_args;
1351                 args [0] = this_arg;
1352                 this_arg = NULL;
1353         }
1354         return mono_runtime_invoke (m, this_arg, args, NULL);
1355 }
1356
1357 void
1358 mono_gsharedvt_value_copy (gpointer dest, gpointer src, MonoClass *klass)
1359 {
1360         if (klass->valuetype)
1361                 mono_value_copy (dest, src, klass);
1362         else
1363         mono_gc_wbarrier_generic_store (dest, *(MonoObject**)src);
1364 }
1365
1366 void
1367 mono_generic_class_init (MonoVTable *vtable)
1368 {
1369         mono_runtime_class_init (vtable);
1370 }
1371
1372 gpointer
1373 mono_fill_class_rgctx (MonoVTable *vtable, int index)
1374 {
1375         MonoError error;
1376         gpointer res;
1377
1378         res = mono_class_fill_runtime_generic_context (vtable, index, &error);
1379         if (!mono_error_ok (&error)) {
1380                 mono_error_set_pending_exception (&error);
1381                 return NULL;
1382         }
1383         return res;
1384 }
1385
1386 gpointer
1387 mono_fill_method_rgctx (MonoMethodRuntimeGenericContext *mrgctx, int index)
1388 {
1389         MonoError error;
1390         gpointer res;
1391
1392         res = mono_method_fill_runtime_generic_context (mrgctx, index, &error);
1393         if (!mono_error_ok (&error)) {
1394                 mono_error_set_pending_exception (&error);
1395                 return NULL;
1396         }
1397         return res;
1398 }
1399
1400 /*
1401  * resolve_iface_call:
1402  *
1403  *   Return the executable code for the iface method IMT_METHOD called on THIS.
1404  * This function is called on a slowpath, so it doesn't need to be fast.
1405  * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1406  * out parameter.
1407  */
1408 static gpointer
1409 resolve_iface_call (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg, gboolean caller_gsharedvt)
1410 {
1411         MonoVTable *vt;
1412         gpointer *imt, *vtable_slot;
1413         MonoMethod *impl_method, *generic_virtual = NULL, *variant_iface = NULL;
1414         gpointer addr, compiled_method, aot_addr;
1415         gboolean need_rgctx_tramp = FALSE, need_unbox_tramp = FALSE;
1416
1417         if (!this_obj)
1418                 /* The caller will handle it */
1419                 return NULL;
1420
1421         vt = this_obj->vtable;
1422         imt = (gpointer*)vt - MONO_IMT_SIZE;
1423
1424         vtable_slot = mini_resolve_imt_method (vt, imt + imt_slot, imt_method, &impl_method, &aot_addr, &need_rgctx_tramp, &variant_iface);
1425
1426         // FIXME: This can throw exceptions
1427         addr = compiled_method = mono_compile_method (impl_method);
1428         g_assert (addr);
1429
1430         if (imt_method->is_inflated && ((MonoMethodInflated*)imt_method)->context.method_inst)
1431                 generic_virtual = imt_method;
1432
1433         if (generic_virtual || variant_iface) {
1434                 if (vt->klass->valuetype) /*FIXME is this required variant iface?*/
1435                         need_unbox_tramp = TRUE;
1436         } else {
1437                 if (impl_method->klass->valuetype)
1438                         need_unbox_tramp = TRUE;
1439         }
1440
1441         addr = mini_add_method_wrappers_llvmonly (impl_method, addr, caller_gsharedvt, need_unbox_tramp, out_arg);
1442
1443         if (generic_virtual || variant_iface) {
1444                 MonoMethod *target = generic_virtual ? generic_virtual : variant_iface;
1445
1446                 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1447                                                                                                         vt, imt + imt_slot,
1448                                                                                                         target, addr);
1449         }
1450
1451         return addr;
1452 }
1453
1454 gpointer
1455 mono_resolve_iface_call_gsharedvt (MonoObject *this_obj, int imt_slot, MonoMethod *imt_method, gpointer *out_arg)
1456 {
1457         return resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE);
1458 }
1459
1460 static gboolean
1461 is_generic_method_definition (MonoMethod *m)
1462 {
1463         MonoGenericContext *context;
1464         if (m->is_generic)
1465                 return TRUE;
1466         if (!m->is_inflated)
1467                 return FALSE;
1468
1469         context = mono_method_get_context (m);
1470         if (!context->method_inst)
1471                 return FALSE;
1472         if (context->method_inst == mono_method_get_generic_container (((MonoMethodInflated*)m)->declaring)->context.method_inst)
1473                 return TRUE;
1474         return FALSE;
1475 }
1476
1477 /*
1478  * resolve_vcall:
1479  *
1480  *   Return the executable code for calling vt->vtable [slot].
1481  * This function is called on a slowpath, so it doesn't need to be fast.
1482  * This returns an ftnptr by returning the address part, and the arg in the OUT_ARG
1483  * out parameter.
1484  */
1485 static gpointer
1486 resolve_vcall (MonoVTable *vt, int slot, MonoMethod *imt_method, gpointer *out_arg, gboolean gsharedvt)
1487 {
1488         MonoMethod *m, *generic_virtual = NULL;
1489         gpointer addr, compiled_method;
1490         gboolean need_unbox_tramp = FALSE;
1491
1492         /* Same as in common_call_trampoline () */
1493
1494         /* Avoid loading metadata or creating a generic vtable if possible */
1495         addr = mono_aot_get_method_from_vt_slot (mono_domain_get (), vt, slot);
1496         if (addr && !vt->klass->valuetype)
1497                 return mono_create_ftnptr (mono_domain_get (), addr);
1498
1499         m = mono_class_get_vtable_entry (vt->klass, slot);
1500
1501         if (is_generic_method_definition (m)) {
1502                 MonoError error;
1503                 MonoGenericContext context = { NULL, NULL };
1504                 MonoMethod *declaring;
1505
1506                 if (m->is_inflated)
1507                         declaring = mono_method_get_declaring_generic_method (m);
1508                 else
1509                         declaring = m;
1510
1511                 if (m->klass->generic_class)
1512                         context.class_inst = m->klass->generic_class->context.class_inst;
1513                 else
1514                         g_assert (!m->klass->generic_container);
1515
1516                 generic_virtual = imt_method;
1517                 g_assert (generic_virtual);
1518                 g_assert (generic_virtual->is_inflated);
1519                 context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1520
1521                 m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1522                 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
1523         }
1524
1525         if (generic_virtual) {
1526                 if (vt->klass->valuetype)
1527                         need_unbox_tramp = TRUE;
1528         } else {
1529                 if (m->klass->valuetype)
1530                         need_unbox_tramp = TRUE;
1531         }
1532
1533         // FIXME: This can throw exceptions
1534         addr = compiled_method = mono_compile_method (m);
1535         g_assert (addr);
1536
1537         addr = mini_add_method_wrappers_llvmonly (m, addr, gsharedvt, need_unbox_tramp, out_arg);
1538
1539         if (!gsharedvt && generic_virtual) {
1540                 // FIXME: This wastes memory since add_generic_virtual_invocation ignores it in a lot of cases
1541                 MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, out_arg);
1542
1543                 mono_method_add_generic_virtual_invocation (mono_domain_get (),
1544                                                                                                         vt, vt->vtable + slot,
1545                                                                                                         generic_virtual, ftndesc);
1546         }
1547
1548         return addr;
1549 }
1550
1551 gpointer
1552 mono_resolve_vcall_gsharedvt (MonoObject *this_obj, int slot, MonoMethod *imt_method, gpointer *out_arg)
1553 {
1554         g_assert (this_obj);
1555
1556         return resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE);
1557 }
1558
1559 /*
1560  * mono_resolve_generic_virtual_call:
1561  *
1562  *   Resolve a generic virtual call.
1563  * This function is called on a slowpath, so it doesn't need to be fast.
1564  */
1565 MonoFtnDesc*
1566 mono_resolve_generic_virtual_call (MonoVTable *vt, int slot, MonoMethod *generic_virtual)
1567 {
1568         MonoMethod *m;
1569         gpointer addr, compiled_method;
1570         gboolean need_unbox_tramp = FALSE;
1571         MonoError error;
1572         MonoGenericContext context = { NULL, NULL };
1573         MonoMethod *declaring;
1574         gpointer arg = NULL;
1575
1576         m = mono_class_get_vtable_entry (vt->klass, slot);
1577
1578         g_assert (is_generic_method_definition (m));
1579
1580         if (m->is_inflated)
1581                 declaring = mono_method_get_declaring_generic_method (m);
1582         else
1583                 declaring = m;
1584
1585         if (m->klass->generic_class)
1586                 context.class_inst = m->klass->generic_class->context.class_inst;
1587         else
1588                 g_assert (!m->klass->generic_container);
1589
1590         g_assert (generic_virtual->is_inflated);
1591         context.method_inst = ((MonoMethodInflated*)generic_virtual)->context.method_inst;
1592
1593         m = mono_class_inflate_generic_method_checked (declaring, &context, &error);
1594         g_assert (mono_error_ok (&error));
1595
1596         if (vt->klass->valuetype)
1597                 need_unbox_tramp = TRUE;
1598
1599         // FIXME: This can throw exceptions
1600         addr = compiled_method = mono_compile_method (m);
1601         g_assert (addr);
1602
1603         addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1604
1605         /*
1606          * This wastes memory but the memory usage is bounded since
1607          * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1608          * this vtable slot so we are not called any more for this instantiation.
1609          */
1610         MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1611
1612         mono_method_add_generic_virtual_invocation (mono_domain_get (),
1613                                                                                                 vt, vt->vtable + slot,
1614                                                                                                 generic_virtual, ftndesc);
1615         return ftndesc;
1616 }
1617
1618 /*
1619  * mono_resolve_generic_virtual_call:
1620  *
1621  *   Resolve a generic virtual/variant iface call on interfaces.
1622  * This function is called on a slowpath, so it doesn't need to be fast.
1623  */
1624 MonoFtnDesc*
1625 mono_resolve_generic_virtual_iface_call (MonoVTable *vt, int imt_slot, MonoMethod *generic_virtual)
1626 {
1627         MonoMethod *m, *variant_iface;
1628         gpointer addr, aot_addr, compiled_method;
1629         gboolean need_unbox_tramp = FALSE;
1630         gboolean need_rgctx_tramp;
1631         gpointer arg = NULL;
1632         gpointer *imt;
1633
1634         imt = (gpointer*)vt - MONO_IMT_SIZE;
1635
1636         mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface);
1637
1638         if (vt->klass->valuetype)
1639                 need_unbox_tramp = TRUE;
1640
1641         // FIXME: This can throw exceptions
1642         addr = compiled_method = mono_compile_method (m);
1643         g_assert (addr);
1644
1645         addr = mini_add_method_wrappers_llvmonly (m, addr, FALSE, need_unbox_tramp, &arg);
1646
1647         /*
1648          * This wastes memory but the memory usage is bounded since
1649          * mono_method_add_generic_virtual_invocation () eventually builds an imt thunk for
1650          * this vtable slot so we are not called any more for this instantiation.
1651          */
1652         MonoFtnDesc *ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1653
1654         mono_method_add_generic_virtual_invocation (mono_domain_get (),
1655                                                                                                 vt, imt + imt_slot,
1656                                                                                                 variant_iface ? variant_iface : generic_virtual, ftndesc);
1657         return ftndesc;
1658 }
1659
1660 /*
1661  * mono_init_vtable_slot:
1662  *
1663  *   Initialize slot SLOT of VTABLE.
1664  * Return the contents of the vtable slot.
1665  */
1666 gpointer
1667 mono_init_vtable_slot (MonoVTable *vtable, int slot)
1668 {
1669         gpointer arg = NULL;
1670         gpointer addr;
1671         gpointer *ftnptr;
1672
1673         addr = resolve_vcall (vtable, slot, NULL, &arg, FALSE);
1674         ftnptr = mono_domain_alloc0 (vtable->domain, 2 * sizeof (gpointer));
1675         ftnptr [0] = addr;
1676         ftnptr [1] = arg;
1677         mono_memory_barrier ();
1678
1679         vtable->vtable [slot] = ftnptr;
1680
1681         return ftnptr;
1682 }
1683
1684 /*
1685  * mono_llvmonly_init_delegate:
1686  *
1687  *   Initialize a MonoDelegate object.
1688  * Similar to mono_delegate_ctor ().
1689  */
1690 void
1691 mono_llvmonly_init_delegate (MonoDelegate *del)
1692 {
1693         MonoFtnDesc *ftndesc = *(MonoFtnDesc**)del->method_code;
1694
1695         /*
1696          * We store a MonoFtnDesc in del->method_code.
1697          * It would be better to store an ftndesc in del->method_ptr too,
1698          * but we don't have a a structure which could own its memory.
1699          */
1700         if (G_UNLIKELY (!ftndesc)) {
1701                 gpointer addr = mono_compile_method (del->method);
1702                 gpointer arg = mini_get_delegate_arg (del->method, addr);
1703
1704                 ftndesc = mini_create_llvmonly_ftndesc (mono_domain_get (), addr, arg);
1705                 mono_memory_barrier ();
1706                 *del->method_code = (gpointer)ftndesc;
1707         }
1708         del->method_ptr = ftndesc->addr;
1709         del->extra_arg = ftndesc->arg;
1710 }
1711
1712 void
1713 mono_llvmonly_init_delegate_virtual (MonoDelegate *del, MonoObject *target, MonoMethod *method)
1714 {
1715         g_assert (target);
1716
1717         method = mono_object_get_virtual_method (target, method);
1718
1719         del->method = method;
1720         del->method_ptr = mono_compile_method (method);
1721         del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
1722 }
1723
1724 MonoObject*
1725 mono_get_assembly_object (MonoImage *image)
1726 {
1727         return (MonoObject*)mono_assembly_get_object (mono_domain_get (), image->assembly);
1728 }
1729
1730 MonoObject*
1731 mono_get_method_object (MonoMethod *method)
1732 {
1733         return (MonoObject*)mono_method_get_object (mono_domain_get (), method, method->klass);
1734 }
1735
1736 double
1737 mono_ckfinite (double d)
1738 {
1739         if (isinf (d) || isnan (d))
1740                 mono_set_pending_exception (mono_get_exception_arithmetic ());
1741         return d;
1742 }
1743
1744 void
1745 mono_llvmonly_set_calling_assembly (MonoImage *image)
1746 {
1747         MonoJitTlsData *jit_tls = NULL;
1748
1749         jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1750         g_assert (jit_tls);
1751         jit_tls->calling_image = image;
1752 }
1753
1754
1755 static gboolean
1756 get_executing (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
1757 {
1758         MonoMethod **dest = (MonoMethod **)data;
1759
1760         /* skip unmanaged frames */
1761         if (!managed)
1762                 return FALSE;
1763
1764         if (!(*dest)) {
1765                 if (!strcmp (m->klass->name_space, "System.Reflection"))
1766                         return FALSE;
1767                 *dest = m;
1768                 return TRUE;
1769         }
1770         return FALSE;
1771 }
1772
1773 static gboolean
1774 get_caller_no_reflection (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
1775 {
1776         MonoMethod **dest = (MonoMethod **)data;
1777
1778         /* skip unmanaged frames */
1779         if (!managed)
1780                 return FALSE;
1781
1782         if (m->wrapper_type != MONO_WRAPPER_NONE)
1783                 return FALSE;
1784
1785         if (m->klass->image == mono_defaults.corlib && !strcmp (m->klass->name_space, "System.Reflection"))
1786                 return FALSE;
1787
1788         if (m == *dest) {
1789                 *dest = NULL;
1790                 return FALSE;
1791         }
1792         if (!(*dest)) {
1793                 *dest = m;
1794                 return TRUE;
1795         }
1796         return FALSE;
1797 }
1798
1799 MonoObject*
1800 mono_llvmonly_get_calling_assembly (void)
1801 {
1802         MonoJitTlsData *jit_tls = NULL;
1803         MonoMethod *m;
1804         MonoMethod *dest;
1805         MonoAssembly *assembly;
1806
1807         dest = NULL;
1808         mono_stack_walk_no_il (get_executing, &dest);
1809         m = dest;
1810         mono_stack_walk_no_il (get_caller_no_reflection, &dest);
1811
1812         if (!dest) {
1813                 /* Fall back to TLS */
1814                 jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id);
1815                 g_assert (jit_tls);
1816                 if (!jit_tls->calling_image) {
1817                         mono_set_pending_exception (mono_get_exception_not_supported ("Stack walks are not supported on this platform."));
1818                         return NULL;
1819                 }
1820                 assembly = jit_tls->calling_image->assembly;
1821         } else {
1822                 assembly = dest->klass->image->assembly;
1823         }
1824         return (MonoObject*)mono_assembly_get_object (mono_domain_get (), jit_tls->calling_image->assembly);
1825 }
1826
1827 /*
1828  * mono_interruption_checkpoint_from_trampoline:
1829  *
1830  *   Check whenever the thread has a pending exception, and throw it
1831  * if needed.
1832  * Architectures should move away from calling this function and
1833  * instead call mono_thread_force_interruption_checkpoint_noraise (),
1834  * rewrind to the parent frame, and throw the exception normally.
1835  */
1836 void
1837 mono_interruption_checkpoint_from_trampoline (void)
1838 {
1839         MonoException *ex;
1840
1841         ex = mono_thread_force_interruption_checkpoint_noraise ();
1842         if (ex)
1843                 mono_raise_exception (ex);
1844 }