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