2009-01-30 Zoltan Varga <vargaz@gmail.com>
[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  */
10 #include <config.h>
11 #include <math.h>
12 #include <limits.h>
13 #ifdef HAVE_ALLOCA_H
14 #include <alloca.h>
15 #endif
16
17 #include "jit-icalls.h"
18
19 void*
20 mono_ldftn (MonoMethod *method)
21 {
22         gpointer addr;
23
24         MONO_ARCH_SAVE_REGS;
25
26         addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
27
28         return mono_create_ftnptr (mono_domain_get (), addr);
29 }
30
31 static void*
32 ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared)
33 {
34         MonoMethod *res;
35
36         MONO_ARCH_SAVE_REGS;
37
38         if (obj == NULL)
39                 mono_raise_exception (mono_get_exception_null_reference ());
40
41         res = mono_object_get_virtual_method (obj, method);
42
43         if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) {
44                 MonoGenericContext context = { NULL, NULL };
45
46                 if (res->klass->generic_class)
47                         context.class_inst = res->klass->generic_class->context.class_inst;
48                 else if (res->klass->generic_container)
49                         context.class_inst = res->klass->generic_container->context.class_inst;
50                 context.method_inst = mono_method_get_context (method)->method_inst;
51
52                 res = mono_class_inflate_generic_method (res, &context);
53         }
54
55         if (mono_method_needs_static_rgctx_invoke (res, FALSE))
56                 res = mono_marshal_get_static_rgctx_invoke (res);
57
58         return mono_ldftn (res);
59 }
60
61 void*
62 mono_ldvirtfn (MonoObject *obj, MonoMethod *method) 
63 {
64         return ldvirtfn_internal (obj, method, FALSE);
65 }
66
67 void*
68 mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method) 
69 {
70         return ldvirtfn_internal (obj, method, TRUE);
71 }
72
73 void
74 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
75 {
76         MONO_ARCH_SAVE_REGS;
77
78         if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
79                 mono_raise_exception (mono_get_exception_array_type_mismatch ());
80 }
81
82 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
83
84 gint64 
85 mono_llmult (gint64 a, gint64 b)
86 {
87         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
88         return a * b;
89 }
90
91 guint64  
92 mono_llmult_ovf_un (guint64 a, guint64 b)
93 {
94         guint32 al = a;
95         guint32 ah = a >> 32;
96         guint32 bl = b;
97         guint32 bh = b >> 32; 
98         guint64 res, t1;
99
100         MONO_ARCH_SAVE_REGS;
101
102         // fixme: this is incredible slow
103
104         if (ah && bh)
105                 goto raise_exception;
106
107         res = (guint64)al * (guint64)bl;
108
109         t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
110
111         if (t1 > 0xffffffff)
112                 goto raise_exception;
113
114         res += ((guint64)t1) << 32; 
115
116         return res;
117
118  raise_exception:
119         mono_raise_exception (mono_get_exception_overflow ());
120         return 0;
121 }
122
123 guint64  
124 mono_llmult_ovf (gint64 a, gint64 b) 
125 {
126         guint32 al = a;
127         gint32 ah = a >> 32;
128         guint32 bl = b;
129         gint32 bh = b >> 32; 
130         /*
131         Use Karatsuba algorithm where:
132                 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
133                 where Ah is the "high half" (most significant 32 bits) of a and
134                 where Al is the "low half" (least significant 32 bits) of a and
135                 where  Bh is the "high half" of b and Bl is the "low half" and
136                 where R is the Radix or "size of the half" (in our case 32 bits)
137
138         Note, for the product of two 64 bit numbers to fit into a 64
139         result, ah and/or bh must be 0.  This will save us from doing
140         the AhBh term at all.
141
142         Also note that we refactor so that we don't overflow 64 bits with 
143         intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
144         */
145
146         gint64 res, t1;
147         gint32 sign;
148
149         MONO_ARCH_SAVE_REGS;
150
151         /* need to work with absoulte values, so find out what the
152            resulting sign will be and convert any negative numbers
153            from two's complement
154         */
155         sign = ah ^ bh;
156         if (ah < 0) {
157                 if (((guint32)ah == 0x80000000) && (al == 0)) {
158                         /* This has no two's complement */
159                         if (b == 0)
160                                 return 0;
161                         else if (b == 1)
162                                 return a;
163                         else
164                                 goto raise_exception;
165                 }
166
167                 /* flip the bits and add 1 */
168                 ah ^= ~0;
169                 if (al ==  0)
170                         ah += 1;
171                 else {
172                         al ^= ~0;
173                         al +=1;
174                 }
175         }
176
177         if (bh < 0) {
178                 if (((guint32)bh == 0x80000000) && (bl == 0)) {
179                         /* This has no two's complement */
180                         if (a == 0)
181                                 return 0;
182                         else if (a == 1)
183                                 return b;
184                         else
185                                 goto raise_exception;
186                 }
187
188                 /* flip the bits and add 1 */
189                 bh ^= ~0;
190                 if (bl ==  0)
191                         bh += 1;
192                 else {
193                         bl ^= ~0;
194                         bl +=1;
195                 }
196         }
197                 
198         /* we overflow for sure if both upper halves are greater 
199            than zero because we would need to shift their 
200            product 64 bits to the left and that will not fit
201            in a 64 bit result */
202         if (ah && bh)
203                 goto raise_exception;
204         if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
205                 goto raise_exception;
206
207         /* do the AlBl term first */
208         t1 = (gint64)al * (gint64)bl;
209
210         res = t1;
211
212         /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
213         t1 += (gint64)(ah - al) * (gint64)(bl - bh);
214         /* check for overflow */
215         t1 <<= 32;
216         if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
217                 goto raise_exception;
218
219         res += t1;
220
221         if (res < 0)
222                 goto raise_exception;
223
224         if (sign < 0)
225                 return -res;
226         else
227                 return res;
228
229  raise_exception:
230         mono_raise_exception (mono_get_exception_overflow ());
231         return 0;
232 }
233
234 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
235
236 gint32
237 mono_idiv (gint32 a, gint32 b)
238 {
239         MONO_ARCH_SAVE_REGS;
240
241 #ifdef MONO_ARCH_NEED_DIV_CHECK
242         if (!b)
243                 mono_raise_exception (mono_get_exception_divide_by_zero ());
244         else if (b == -1 && a == (0x80000000))
245                 mono_raise_exception (mono_get_exception_arithmetic ());
246 #endif
247         return a / b;
248 }
249
250 guint32
251 mono_idiv_un (guint32 a, guint32 b)
252 {
253         MONO_ARCH_SAVE_REGS;
254
255 #ifdef MONO_ARCH_NEED_DIV_CHECK
256         if (!b)
257                 mono_raise_exception (mono_get_exception_divide_by_zero ());
258 #endif
259         return a / b;
260 }
261
262 gint32
263 mono_irem (gint32 a, gint32 b)
264 {
265         MONO_ARCH_SAVE_REGS;
266
267 #ifdef MONO_ARCH_NEED_DIV_CHECK
268         if (!b)
269                 mono_raise_exception (mono_get_exception_divide_by_zero ());
270         else if (b == -1 && a == (0x80000000))
271                 mono_raise_exception (mono_get_exception_arithmetic ());
272 #endif
273
274         return a % b;
275 }
276
277 guint32
278 mono_irem_un (guint32 a, guint32 b)
279 {
280         MONO_ARCH_SAVE_REGS;
281
282 #ifdef MONO_ARCH_NEED_DIV_CHECK
283         if (!b)
284                 mono_raise_exception (mono_get_exception_divide_by_zero ());
285 #endif
286         return a % b;
287 }
288
289 #endif
290
291 #ifdef MONO_ARCH_EMULATE_MUL_DIV
292
293 gint32
294 mono_imul (gint32 a, gint32 b)
295 {
296         MONO_ARCH_SAVE_REGS;
297
298         return a * b;
299 }
300
301 gint32
302 mono_imul_ovf (gint32 a, gint32 b)
303 {
304         gint64 res;
305
306         MONO_ARCH_SAVE_REGS;
307
308         res = (gint64)a * (gint64)b;
309
310         if ((res > 0x7fffffffL) || (res < -2147483648))
311                 mono_raise_exception (mono_get_exception_overflow ());
312
313         return res;
314 }
315
316 gint32
317 mono_imul_ovf_un (guint32 a, guint32 b)
318 {
319         guint64 res;
320
321         MONO_ARCH_SAVE_REGS;
322
323         res = (guint64)a * (guint64)b;
324
325         if ((res >> 32))
326                 mono_raise_exception (mono_get_exception_overflow ());
327
328         return res;
329 }
330 #endif
331
332 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
333 double
334 mono_fdiv (double a, double b)
335 {
336         MONO_ARCH_SAVE_REGS;
337
338         return a / b;
339 }
340 #endif
341
342 gint64 
343 mono_lldiv (gint64 a, gint64 b)
344 {
345         MONO_ARCH_SAVE_REGS;
346
347 #ifdef MONO_ARCH_NEED_DIV_CHECK
348         if (!b)
349                 mono_raise_exception (mono_get_exception_divide_by_zero ());
350         else if (b == -1 && a == (-9223372036854775807LL - 1LL))
351                 mono_raise_exception (mono_get_exception_arithmetic ());
352 #endif
353         return a / b;
354 }
355
356 gint64 
357 mono_llrem (gint64 a, gint64 b)
358 {
359         MONO_ARCH_SAVE_REGS;
360
361 #ifdef MONO_ARCH_NEED_DIV_CHECK
362         if (!b)
363                 mono_raise_exception (mono_get_exception_divide_by_zero ());
364         else if (b == -1 && a == (-9223372036854775807LL - 1LL))
365                 mono_raise_exception (mono_get_exception_arithmetic ());
366 #endif
367         return a % b;
368 }
369
370 guint64 
371 mono_lldiv_un (guint64 a, guint64 b)
372 {
373         MONO_ARCH_SAVE_REGS;
374
375 #ifdef MONO_ARCH_NEED_DIV_CHECK
376         if (!b)
377                 mono_raise_exception (mono_get_exception_divide_by_zero ());
378 #endif
379         return a / b;
380 }
381
382 guint64 
383 mono_llrem_un (guint64 a, guint64 b)
384 {
385         MONO_ARCH_SAVE_REGS;
386
387 #ifdef MONO_ARCH_NEED_DIV_CHECK
388         if (!b)
389                 mono_raise_exception (mono_get_exception_divide_by_zero ());
390 #endif
391         return a % b;
392 }
393
394 #endif
395
396 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
397
398 guint64 
399 mono_lshl (guint64 a, gint32 shamt)
400 {
401         guint64 res;
402
403         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
404         res = a << shamt;
405
406         /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
407
408         return res;
409 }
410
411 guint64 
412 mono_lshr_un (guint64 a, gint32 shamt)
413 {
414         guint64 res;
415
416         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
417         res = a >> shamt;
418
419         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
420
421         return res;
422 }
423
424 gint64 
425 mono_lshr (gint64 a, gint32 shamt)
426 {
427         gint64 res;
428
429         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
430         res = a >> shamt;
431
432         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
433
434         return res;
435 }
436
437 #endif
438
439 #ifdef MONO_ARCH_SOFT_FLOAT
440
441 double
442 mono_fsub (double a, double b)
443 {
444         return a - b;
445 }
446
447 double
448 mono_fadd (double a, double b)
449 {
450         return a + b;
451 }
452
453 double
454 mono_fmul (double a, double b)
455 {
456         return a * b;
457 }
458
459 double
460 mono_fneg (double a)
461 {
462         return -a;
463 }
464
465 double
466 mono_fconv_r4 (double a)
467 {
468         return (float)a;
469 }
470
471 double
472 mono_conv_to_r8 (int a)
473 {
474         return (double)a;
475 }
476
477 double
478 mono_conv_to_r4 (int a)
479 {
480         return (double)(float)a;
481 }
482
483 gint8
484 mono_fconv_i1 (double a)
485 {
486         return (gint8)a;
487 }
488
489 gint16
490 mono_fconv_i2 (double a)
491 {
492         return (gint16)a;
493 }
494
495 gint32
496 mono_fconv_i4 (double a)
497 {
498         return (gint32)a;
499 }
500
501 guint8
502 mono_fconv_u1 (double a)
503 {
504         return (guint8)a;
505 }
506
507 guint16
508 mono_fconv_u2 (double a)
509 {
510         return (guint16)a;
511 }
512
513 gboolean
514 mono_fcmp_eq (double a, double b)
515 {
516         return a == b;
517 }
518
519 gboolean
520 mono_fcmp_ge (double a, double b)
521 {
522         return a >= b;
523 }
524
525 gboolean
526 mono_fcmp_gt (double a, double b)
527 {
528         return a > b;
529 }
530
531 gboolean
532 mono_fcmp_le (double a, double b)
533 {
534         return a <= b;
535 }
536
537 gboolean
538 mono_fcmp_lt (double a, double b)
539 {
540         return a < b;
541 }
542
543 gboolean
544 mono_fcmp_ne_un (double a, double b)
545 {
546         return isunordered (a, b) || a != b;
547 }
548
549 gboolean
550 mono_fcmp_ge_un (double a, double b)
551 {
552         return isunordered (a, b) || a >= b;
553 }
554
555 gboolean
556 mono_fcmp_gt_un (double a, double b)
557 {
558         return isunordered (a, b) || a > b;
559 }
560
561 gboolean
562 mono_fcmp_le_un (double a, double b)
563 {
564         return isunordered (a, b) || a <= b;
565 }
566
567 gboolean
568 mono_fcmp_lt_un (double a, double b)
569 {
570         return isunordered (a, b) || a < b;
571 }
572
573 gboolean
574 mono_fceq (double a, double b)
575 {
576         return a == b;
577 }
578
579 gboolean
580 mono_fcgt (double a, double b)
581 {
582         return a > b;
583 }
584
585 gboolean
586 mono_fcgt_un (double a, double b)
587 {
588         return isunordered (a, b) || a > b;
589 }
590
591 gboolean
592 mono_fclt (double a, double b)
593 {
594         return a < b;
595 }
596
597 gboolean
598 mono_fclt_un (double a, double b)
599 {
600         return isunordered (a, b) || a < b;
601 }
602
603 gboolean
604 mono_isfinite (double a)
605 {
606 #ifdef HAVE_ISFINITE
607         return isfinite (a);
608 #else
609         g_assert_not_reached ();
610         return TRUE;
611 #endif
612 }
613
614 double
615 mono_fload_r4 (float *ptr)
616 {
617         return *ptr;
618 }
619
620 void
621 mono_fstore_r4 (double val, float *ptr)
622 {
623         *ptr = (float)val;
624 }
625
626 /* returns the integer bitpattern that is passed in the regs or stack */
627 guint32
628 mono_fload_r4_arg (double val)
629 {
630         float v = (float)val;
631         return *(guint32*)&v;
632 }
633
634 #endif
635
636 MonoArray *
637 mono_array_new_va (MonoMethod *cm, ...)
638 {
639         MonoDomain *domain = mono_domain_get ();
640         va_list ap;
641         guint32 *lengths;
642         guint32 *lower_bounds;
643         int pcount;
644         int rank;
645         int i, d;
646
647         MONO_ARCH_SAVE_REGS;
648
649         pcount = mono_method_signature (cm)->param_count;
650         rank = cm->klass->rank;
651
652         va_start (ap, cm);
653         
654         lengths = alloca (sizeof (guint32) * pcount);
655         for (i = 0; i < pcount; ++i)
656                 lengths [i] = d = va_arg(ap, int);
657
658         if (rank == pcount) {
659                 /* Only lengths provided. */
660                 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
661                         lower_bounds = alloca (sizeof (guint32) * rank);
662                         memset (lower_bounds, 0, sizeof (guint32) * rank);
663                 } else {
664                         lower_bounds = NULL;
665                 }
666         } else {
667                 g_assert (pcount == (rank * 2));
668                 /* lower bounds are first. */
669                 lower_bounds = lengths;
670                 lengths += rank;
671         }
672         va_end(ap);
673
674         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
675 }
676
677 /* Specialized version of mono_array_new_va () which avoids varargs */
678 MonoArray *
679 mono_array_new_1 (MonoMethod *cm, guint32 length)
680 {
681         MonoDomain *domain = mono_domain_get ();
682         guint32 lengths [1];
683         guint32 *lower_bounds;
684         int pcount;
685         int rank;
686
687         MONO_ARCH_SAVE_REGS;
688
689         pcount = mono_method_signature (cm)->param_count;
690         rank = cm->klass->rank;
691
692         lengths [0] = length;
693
694         g_assert (rank == pcount);
695
696         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
697                 lower_bounds = alloca (sizeof (guint32) * rank);
698                 memset (lower_bounds, 0, sizeof (guint32) * rank);
699         } else {
700                 lower_bounds = NULL;
701         }
702
703         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
704 }
705
706 MonoArray *
707 mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2)
708 {
709         MonoDomain *domain = mono_domain_get ();
710         guint32 lengths [2];
711         guint32 *lower_bounds;
712         int pcount;
713         int rank;
714
715         MONO_ARCH_SAVE_REGS;
716
717         pcount = mono_method_signature (cm)->param_count;
718         rank = cm->klass->rank;
719
720         lengths [0] = length1;
721         lengths [1] = length2;
722
723         g_assert (rank == pcount);
724
725         if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
726                 lower_bounds = alloca (sizeof (guint32) * rank);
727                 memset (lower_bounds, 0, sizeof (guint32) * rank);
728         } else {
729                 lower_bounds = NULL;
730         }
731
732         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
733 }
734
735 gpointer
736 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
737 {
738         MonoVTable *vtable;
739         gpointer addr;
740         
741         MONO_ARCH_SAVE_REGS;
742
743         //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
744
745         mono_class_init (field->parent);
746
747         vtable = mono_class_vtable (domain, field->parent);
748         if (!vtable->initialized)
749                 mono_runtime_class_init (vtable);
750
751         //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
752
753         if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
754                 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
755         else
756                 addr = (char*)vtable->data + field->offset;
757         
758         return addr;
759 }
760
761 gpointer
762 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
763 {
764         MonoClass *handle_class;
765         gpointer res;
766
767         MONO_ARCH_SAVE_REGS;
768         res = mono_ldtoken (image, token, &handle_class, context);      
769         mono_class_init (handle_class);
770
771         return res;
772 }
773
774 gpointer
775 mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method)
776 {
777         MonoMethodSignature *sig = mono_method_signature (method);
778         MonoGenericContext *generic_context;
779
780         if (sig->is_inflated) {
781                 generic_context = mono_method_get_context (method);
782         } else {
783                 MonoGenericContainer *generic_container = mono_method_get_generic_container (method);
784                 g_assert (generic_container);
785                 generic_context = &generic_container->context;
786         }
787
788         return mono_ldtoken_wrapper (image, token, generic_context);
789 }
790
791 guint64
792 mono_fconv_u8 (double v)
793 {
794         return (guint64)v;
795 }
796
797 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
798 gint64
799 mono_fconv_i8 (double v)
800 {
801         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
802         return (gint64)v;
803 }
804 #endif
805
806 guint32
807 mono_fconv_u4 (double v)
808 {
809         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
810         return (guint32)v;
811 }
812
813 #ifndef HAVE_TRUNC
814 /* Solaris doesn't have trunc */
815 #ifdef HAVE_AINTL
816 extern long double aintl (long double);
817 #define trunc aintl
818 #else
819 /* FIXME: This means we will never throw overflow exceptions */
820 #define trunc(v) res
821 #endif
822 #endif /* HAVE_TRUNC */
823
824 gint64
825 mono_fconv_ovf_i8 (double v)
826 {
827         gint64 res;
828
829         MONO_ARCH_SAVE_REGS;
830
831         res = (gint64)v;
832
833         if (isnan(v) || trunc (v) != res) {
834                 mono_raise_exception (mono_get_exception_overflow ());
835         }
836         return res;
837 }
838
839 guint64
840 mono_fconv_ovf_u8 (double v)
841 {
842         guint64 res;
843
844         MONO_ARCH_SAVE_REGS;
845 /*
846  * The soft-float implementation of some ARM devices have a buggy guin64 to double
847  * conversion that it looses precision even when the integer if fully representable
848  * as a double.
849  * 
850  * This was found with 4294967295ull, converting to double and back looses one bit of precision.
851  * 
852  * To work around this issue we test for value boundaries instead. 
853  */
854 #if defined(__arm__) && MONO_ARCH_SOFT_FLOAT 
855         if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
856                 mono_raise_exception (mono_get_exception_overflow ());
857         }
858         res = (guint64)v;
859 #else
860         res = (guint64)v;
861         if (isnan(v) || trunc (v) != res) {
862                 mono_raise_exception (mono_get_exception_overflow ());
863         }
864 #endif
865         return res;
866 }
867
868 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
869 double
870 mono_lconv_to_r8 (gint64 a)
871 {
872         return (double)a;
873 }
874 #endif
875
876 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
877 float
878 mono_lconv_to_r4 (gint64 a)
879 {
880         return (float)a;
881 }
882 #endif
883
884 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
885 double
886 mono_conv_to_r8_un (guint32 a)
887 {
888         return (double)a;
889 }
890 #endif
891
892 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
893 double
894 mono_lconv_to_r8_un (guint64 a)
895 {
896         return (double)a;
897 }
898 #endif
899
900 gpointer
901 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg)
902 {
903         MonoMethod *vmethod, *inflated;
904         gpointer addr;
905         MonoGenericContext *context = mono_method_get_context (method);
906
907         mono_jit_stats.generic_virtual_invocations++;
908
909         if (obj == NULL)
910                 mono_raise_exception (mono_get_exception_null_reference ());
911         vmethod = mono_object_get_virtual_method (obj, method);
912
913         /* 'vmethod' is partially inflated.  All the blanks corresponding to the type parameters of the
914            declaring class have been inflated.  We still need to fully inflate the method parameters.
915
916            FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with 
917            the same context.
918         */
919         g_assert (!vmethod->klass->generic_container);
920         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open);
921         g_assert (!context->method_inst || !context->method_inst->is_open);
922         inflated = mono_class_inflate_generic_method (vmethod, context);
923         if (mono_method_needs_static_rgctx_invoke (inflated, FALSE))
924                 inflated = mono_marshal_get_static_rgctx_invoke (inflated);
925         addr = mono_compile_method (inflated);
926
927         /* Since this is a virtual call, have to unbox vtypes */
928         if (obj->vtable->klass->valuetype)
929                 *this_arg = mono_object_unbox (obj);
930         else
931                 *this_arg = obj;
932
933         return addr;
934 }
935
936 MonoString*
937 mono_helper_ldstr (MonoImage *image, guint32 idx)
938 {
939         return mono_ldstr (mono_domain_get (), image, idx);
940 }
941
942 MonoString*
943 mono_helper_ldstr_mscorlib (guint32 idx)
944 {
945         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
946 }
947
948 MonoObject*
949 mono_helper_newobj_mscorlib (guint32 idx)
950 {
951         MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
952         
953         g_assert (klass);
954
955         return mono_object_new (mono_domain_get (), klass);
956 }
957
958 /*
959  * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions
960  * in generated code. So instead we emit a call to this function and place a gdb
961  * breakpoint here.
962  */
963 void
964 mono_break (void)
965 {
966 }
967
968 MonoException *
969 mono_create_corlib_exception_0 (guint32 token)
970 {
971         return mono_exception_from_token (mono_defaults.corlib, token);
972 }
973
974 MonoException *
975 mono_create_corlib_exception_1 (guint32 token, MonoString *arg)
976 {
977         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL);
978 }
979
980 MonoException *
981 mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2)
982 {
983         return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2);
984 }
985
986 MonoObject*
987 mono_object_castclass (MonoObject *obj, MonoClass *klass)
988 {
989         if (!obj)
990                 return NULL;
991
992         if (mono_object_isinst (obj, klass))
993                 return obj;
994
995         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
996                                         "System", "InvalidCastException"));
997
998         return NULL;
999 }