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