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