2006-07-08 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
11 #include <math.h>
12
13 #include "jit-icalls.h"
14
15 void*
16 mono_ldftn (MonoMethod *method)
17 {
18         gpointer addr;
19
20         MONO_ARCH_SAVE_REGS;
21
22         addr = mono_create_jump_trampoline (mono_domain_get (), method, TRUE);
23
24         return mono_create_ftnptr (mono_domain_get (), addr);
25 }
26
27 /*
28  * Same as mono_ldftn, but do not add a synchronized wrapper. Used in the
29  * synchronized wrappers to avoid infinite recursion.
30  */
31 void*
32 mono_ldftn_nosync (MonoMethod *method)
33 {
34         gpointer addr;
35
36         MONO_ARCH_SAVE_REGS;
37
38         addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
39
40         return mono_create_ftnptr (mono_domain_get (), addr);
41 }
42
43 void*
44 mono_ldvirtfn (MonoObject *obj, MonoMethod *method) 
45 {
46         MONO_ARCH_SAVE_REGS;
47
48         if (obj == NULL)
49                 mono_raise_exception (mono_get_exception_null_reference ());
50
51         method = mono_object_get_virtual_method (obj, method);
52
53         return mono_ldftn (method);
54 }
55
56 void
57 mono_helper_stelem_ref (MonoArray *array, int index, MonoObject *val)
58 {
59         MONO_ARCH_SAVE_REGS;
60
61         if (index >= array->max_length)
62                 mono_raise_exception (mono_get_exception_index_out_of_range ());
63
64         if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
65                 mono_raise_exception (mono_get_exception_array_type_mismatch ());
66
67         mono_array_set (array, gpointer, index, val);
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
328 double
329 mono_fdiv (double a, double b)
330 {
331         MONO_ARCH_SAVE_REGS;
332
333         return a / b;
334 }
335 #endif
336
337 gint64 
338 mono_lldiv (gint64 a, gint64 b)
339 {
340         MONO_ARCH_SAVE_REGS;
341
342 #ifdef MONO_ARCH_NEED_DIV_CHECK
343         if (!b)
344                 mono_raise_exception (mono_get_exception_divide_by_zero ());
345         else if (b == -1 && a == (-9223372036854775807LL - 1LL))
346                 mono_raise_exception (mono_get_exception_arithmetic ());
347 #endif
348         return a / b;
349 }
350
351 gint64 
352 mono_llrem (gint64 a, gint64 b)
353 {
354         MONO_ARCH_SAVE_REGS;
355
356 #ifdef MONO_ARCH_NEED_DIV_CHECK
357         if (!b)
358                 mono_raise_exception (mono_get_exception_divide_by_zero ());
359         else if (b == -1 && a == (-9223372036854775807LL - 1LL))
360                 mono_raise_exception (mono_get_exception_arithmetic ());
361 #endif
362         return a % b;
363 }
364
365 guint64 
366 mono_lldiv_un (guint64 a, guint64 b)
367 {
368         MONO_ARCH_SAVE_REGS;
369
370 #ifdef MONO_ARCH_NEED_DIV_CHECK
371         if (!b)
372                 mono_raise_exception (mono_get_exception_divide_by_zero ());
373 #endif
374         return a / b;
375 }
376
377 guint64 
378 mono_llrem_un (guint64 a, guint64 b)
379 {
380         MONO_ARCH_SAVE_REGS;
381
382 #ifdef MONO_ARCH_NEED_DIV_CHECK
383         if (!b)
384                 mono_raise_exception (mono_get_exception_divide_by_zero ());
385 #endif
386         return a % b;
387 }
388
389 #endif
390
391 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
392
393 guint64 
394 mono_lshl (guint64 a, gint32 shamt)
395 {
396         guint64 res;
397
398         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
399         res = a << shamt;
400
401         /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
402
403         return res;
404 }
405
406 guint64 
407 mono_lshr_un (guint64 a, gint32 shamt)
408 {
409         guint64 res;
410
411         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
412         res = a >> shamt;
413
414         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
415
416         return res;
417 }
418
419 gint64 
420 mono_lshr (gint64 a, gint32 shamt)
421 {
422         gint64 res;
423
424         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
425         res = a >> shamt;
426
427         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
428
429         return res;
430 }
431
432 #endif
433
434 /**
435  * ves_array_element_address:
436  * @this: a pointer to the array object
437  *
438  * Returns: the address of an array element.
439  */
440 gpointer 
441 ves_array_element_address (MonoArray *this, ...)
442 {
443         MonoClass *class;
444         va_list ap;
445         int i, ind, esize, realidx;
446         gpointer ea;
447
448         MONO_ARCH_SAVE_REGS;
449
450         g_assert (this != NULL);
451
452         va_start(ap, this);
453
454         class = this->obj.vtable->klass;
455
456         g_assert (this->bounds != NULL);
457
458         esize = mono_array_element_size (class);
459         ind = va_arg(ap, int);
460         ind -= (int)this->bounds [0].lower_bound;
461         if ((guint32)ind >= (guint32)this->bounds [0].length)
462                 mono_raise_exception (mono_get_exception_index_out_of_range ());
463         for (i = 1; i < class->rank; i++) {
464                 realidx = va_arg(ap, int) - (int)this->bounds [i].lower_bound;
465                 if ((guint32)realidx >= (guint32)this->bounds [i].length)
466                         mono_raise_exception (mono_get_exception_index_out_of_range ());
467                 ind *= this->bounds [i].length;
468                 ind += realidx;
469         }
470         esize *= ind;
471
472         ea = (gpointer*)(gpointer)((char*)this->vector + esize);
473
474         va_end(ap);
475
476         return ea;
477 }
478
479 MonoArray *
480 mono_array_new_va (MonoMethod *cm, ...)
481 {
482         MonoDomain *domain = mono_domain_get ();
483         va_list ap;
484         guint32 *lengths;
485         guint32 *lower_bounds;
486         int pcount;
487         int rank;
488         int i, d;
489
490         MONO_ARCH_SAVE_REGS;
491
492         pcount = mono_method_signature (cm)->param_count;
493         rank = cm->klass->rank;
494
495         va_start (ap, cm);
496         
497         lengths = alloca (sizeof (guint32) * pcount);
498         for (i = 0; i < pcount; ++i)
499                 lengths [i] = d = va_arg(ap, int);
500
501         if (rank == pcount) {
502                 /* Only lengths provided. */
503                 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
504                         lower_bounds = alloca (sizeof (guint32) * rank);
505                         memset (lower_bounds, 0, sizeof (guint32) * rank);
506                 } else {
507                         lower_bounds = NULL;
508                 }
509         } else {
510                 g_assert (pcount == (rank * 2));
511                 /* lower bounds are first. */
512                 lower_bounds = lengths;
513                 lengths += rank;
514         }
515         va_end(ap);
516
517         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
518 }
519
520 gpointer
521 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
522 {
523         MonoVTable *vtable;
524         gpointer addr;
525         
526         MONO_ARCH_SAVE_REGS;
527
528         //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
529
530         mono_class_init (field->parent);
531
532         vtable = mono_class_vtable (domain, field->parent);
533         if (!vtable->initialized)
534                 mono_runtime_class_init (vtable);
535
536         //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
537
538         if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
539                 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
540         else
541                 addr = (char*)vtable->data + field->offset;
542         
543         return addr;
544 }
545
546 gpointer
547 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
548 {
549         MonoClass *handle_class;
550         gpointer res;
551
552         MONO_ARCH_SAVE_REGS;
553         res = mono_ldtoken (image, token, &handle_class, context);      
554         mono_class_init (handle_class);
555
556         return res;
557 }
558
559 guint64
560 mono_fconv_u8 (double v)
561 {
562         return (guint64)v;
563 }
564
565 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
566 gint64
567 mono_fconv_i8 (double v)
568 {
569         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
570         return (gint64)v;
571 }
572 #endif
573
574 guint32
575 mono_fconv_u4 (double v)
576 {
577         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
578         return (guint32)v;
579 }
580
581 #ifndef HAVE_TRUNC
582 /* Solaris doesn't have trunc */
583 #ifdef HAVE_AINTL
584 extern long double aintl (long double);
585 #define trunc aintl
586 #else
587 /* FIXME: This means we will never throw overflow exceptions */
588 #define trunc(v) res
589 #endif
590 #endif /* HAVE_TRUNC */
591
592 gint64
593 mono_fconv_ovf_i8 (double v)
594 {
595         gint64 res;
596
597         MONO_ARCH_SAVE_REGS;
598
599         res = (gint64)v;
600
601         if (isnan(v) || trunc (v) != res) {
602                 mono_raise_exception (mono_get_exception_overflow ());
603         }
604         return res;
605 }
606
607 guint64
608 mono_fconv_ovf_u8 (double v)
609 {
610         guint64 res;
611
612         MONO_ARCH_SAVE_REGS;
613     
614         res = (guint64)v;
615
616         if (isnan(v) || trunc (v) != res) {
617                 mono_raise_exception (mono_get_exception_overflow ());
618         }
619         return res;
620 }
621
622 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
623 double
624 mono_lconv_to_r8 (gint64 a)
625 {
626         return (double)a;
627 }
628 #endif
629
630 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
631 float
632 mono_lconv_to_r4 (gint64 a)
633 {
634         return (float)a;
635 }
636 #endif
637
638 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
639 double
640 mono_conv_to_r8_un (guint32 a)
641 {
642         return (double)a;
643 }
644 #endif
645
646 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
647 double
648 mono_lconv_to_r8_un (guint64 a)
649 {
650         return (double)a;
651 }
652 #endif
653
654 gpointer
655 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context)
656 {
657         MonoMethod *vmethod, *inflated;
658         gpointer addr;
659
660         if (obj == NULL)
661                 mono_raise_exception (mono_get_exception_null_reference ());
662         vmethod = mono_object_get_virtual_method (obj, method);
663
664         /* 'vmethod' is partially inflated.  All the blanks corresponding to the type parameters of the
665            declaring class have been inflated.  We still need to fully inflate the method parameters.
666
667            FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with 
668            the same context.
669         */
670         g_assert (!vmethod->klass->generic_container);
671         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->inst->is_open);
672         g_assert (!context->gmethod || !context->gmethod->inst->is_open);
673         inflated = mono_class_inflate_generic_method (vmethod, context);
674         inflated = mono_get_inflated_method (inflated);
675         addr = mono_compile_method (inflated);
676
677         return addr;
678 }
679
680 MonoString*
681 mono_helper_ldstr (MonoImage *image, guint32 idx)
682 {
683         return mono_ldstr (mono_domain_get (), image, idx);
684 }
685
686 MonoString*
687 mono_helper_ldstr_mscorlib (guint32 idx)
688 {
689         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
690 }
691
692 MonoObject*
693 mono_helper_newobj_mscorlib (guint32 idx)
694 {
695         MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
696         
697         g_assert (klass);
698
699         return mono_object_new (mono_domain_get (), klass);
700 }