New test.
[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_check (MonoArray *array, MonoObject *val)
58 {
59         MONO_ARCH_SAVE_REGS;
60
61         if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
62                 mono_raise_exception (mono_get_exception_array_type_mismatch ());
63 }
64
65 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
66
67 gint64 
68 mono_llmult (gint64 a, gint64 b)
69 {
70         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
71         return a * b;
72 }
73
74 guint64  
75 mono_llmult_ovf_un (guint64 a, guint64 b)
76 {
77         guint32 al = a;
78         guint32 ah = a >> 32;
79         guint32 bl = b;
80         guint32 bh = b >> 32; 
81         guint64 res, t1;
82
83         MONO_ARCH_SAVE_REGS;
84
85         // fixme: this is incredible slow
86
87         if (ah && bh)
88                 goto raise_exception;
89
90         res = (guint64)al * (guint64)bl;
91
92         t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
93
94         if (t1 > 0xffffffff)
95                 goto raise_exception;
96
97         res += ((guint64)t1) << 32; 
98
99         return res;
100
101  raise_exception:
102         mono_raise_exception (mono_get_exception_overflow ());
103         return 0;
104 }
105
106 guint64  
107 mono_llmult_ovf (gint64 a, gint64 b) 
108 {
109         guint32 al = a;
110         gint32 ah = a >> 32;
111         guint32 bl = b;
112         gint32 bh = b >> 32; 
113         /*
114         Use Karatsuba algorithm where:
115                 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
116                 where Ah is the "high half" (most significant 32 bits) of a and
117                 where Al is the "low half" (least significant 32 bits) of a and
118                 where  Bh is the "high half" of b and Bl is the "low half" and
119                 where R is the Radix or "size of the half" (in our case 32 bits)
120
121         Note, for the product of two 64 bit numbers to fit into a 64
122         result, ah and/or bh must be 0.  This will save us from doing
123         the AhBh term at all.
124
125         Also note that we refactor so that we don't overflow 64 bits with 
126         intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
127         */
128
129         gint64 res, t1;
130         gint32 sign;
131
132         MONO_ARCH_SAVE_REGS;
133
134         /* need to work with absoulte values, so find out what the
135            resulting sign will be and convert any negative numbers
136            from two's complement
137         */
138         sign = ah ^ bh;
139         if (ah < 0) {
140                 if (((guint32)ah == 0x80000000) && (al == 0)) {
141                         /* This has no two's complement */
142                         if (b == 0)
143                                 return 0;
144                         else if (b == 1)
145                                 return a;
146                         else
147                                 goto raise_exception;
148                 }
149
150                 /* flip the bits and add 1 */
151                 ah ^= ~0;
152                 if (al ==  0)
153                         ah += 1;
154                 else {
155                         al ^= ~0;
156                         al +=1;
157                 }
158         }
159
160         if (bh < 0) {
161                 if (((guint32)bh == 0x80000000) && (bl == 0)) {
162                         /* This has no two's complement */
163                         if (a == 0)
164                                 return 0;
165                         else if (a == 1)
166                                 return b;
167                         else
168                                 goto raise_exception;
169                 }
170
171                 /* flip the bits and add 1 */
172                 bh ^= ~0;
173                 if (bl ==  0)
174                         bh += 1;
175                 else {
176                         bl ^= ~0;
177                         bl +=1;
178                 }
179         }
180                 
181         /* we overflow for sure if both upper halves are greater 
182            than zero because we would need to shift their 
183            product 64 bits to the left and that will not fit
184            in a 64 bit result */
185         if (ah && bh)
186                 goto raise_exception;
187         if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
188                 goto raise_exception;
189
190         /* do the AlBl term first */
191         t1 = (gint64)al * (gint64)bl;
192
193         res = t1;
194
195         /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
196         t1 += (gint64)(ah - al) * (gint64)(bl - bh);
197         /* check for overflow */
198         t1 <<= 32;
199         if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
200                 goto raise_exception;
201
202         res += t1;
203
204         if (res < 0)
205                 goto raise_exception;
206
207         if (sign < 0)
208                 return -res;
209         else
210                 return res;
211
212  raise_exception:
213         mono_raise_exception (mono_get_exception_overflow ());
214         return 0;
215 }
216
217 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
218
219 gint32
220 mono_idiv (gint32 a, gint32 b)
221 {
222         MONO_ARCH_SAVE_REGS;
223
224 #ifdef MONO_ARCH_NEED_DIV_CHECK
225         if (!b)
226                 mono_raise_exception (mono_get_exception_divide_by_zero ());
227         else if (b == -1 && a == (0x80000000))
228                 mono_raise_exception (mono_get_exception_arithmetic ());
229 #endif
230         return a / b;
231 }
232
233 guint32
234 mono_idiv_un (guint32 a, guint32 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 #endif
242         return a / b;
243 }
244
245 gint32
246 mono_irem (gint32 a, gint32 b)
247 {
248         MONO_ARCH_SAVE_REGS;
249
250 #ifdef MONO_ARCH_NEED_DIV_CHECK
251         if (!b)
252                 mono_raise_exception (mono_get_exception_divide_by_zero ());
253         else if (b == -1 && a == (0x80000000))
254                 mono_raise_exception (mono_get_exception_arithmetic ());
255 #endif
256
257         return a % b;
258 }
259
260 guint32
261 mono_irem_un (guint32 a, guint32 b)
262 {
263         MONO_ARCH_SAVE_REGS;
264
265 #ifdef MONO_ARCH_NEED_DIV_CHECK
266         if (!b)
267                 mono_raise_exception (mono_get_exception_divide_by_zero ());
268 #endif
269         return a % b;
270 }
271
272 #endif
273
274 #ifdef MONO_ARCH_EMULATE_MUL_DIV
275
276 gint32
277 mono_imul (gint32 a, gint32 b)
278 {
279         MONO_ARCH_SAVE_REGS;
280
281         return a * b;
282 }
283
284 gint32
285 mono_imul_ovf (gint32 a, gint32 b)
286 {
287         gint64 res;
288
289         MONO_ARCH_SAVE_REGS;
290
291         res = (gint64)a * (gint64)b;
292
293         if ((res > 0x7fffffffL) || (res < -2147483648))
294                 mono_raise_exception (mono_get_exception_overflow ());
295
296         return res;
297 }
298
299 gint32
300 mono_imul_ovf_un (guint32 a, guint32 b)
301 {
302         guint64 res;
303
304         MONO_ARCH_SAVE_REGS;
305
306         res = (guint64)a * (guint64)b;
307
308         if ((res >> 32))
309                 mono_raise_exception (mono_get_exception_overflow ());
310
311         return res;
312 }
313
314 double
315 mono_fdiv (double a, double b)
316 {
317         MONO_ARCH_SAVE_REGS;
318
319         return a / b;
320 }
321 #endif
322
323 gint64 
324 mono_lldiv (gint64 a, gint64 b)
325 {
326         MONO_ARCH_SAVE_REGS;
327
328 #ifdef MONO_ARCH_NEED_DIV_CHECK
329         if (!b)
330                 mono_raise_exception (mono_get_exception_divide_by_zero ());
331         else if (b == -1 && a == (-9223372036854775807LL - 1LL))
332                 mono_raise_exception (mono_get_exception_arithmetic ());
333 #endif
334         return a / b;
335 }
336
337 gint64 
338 mono_llrem (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 guint64 
352 mono_lldiv_un (guint64 a, guint64 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 #endif
360         return a / b;
361 }
362
363 guint64 
364 mono_llrem_un (guint64 a, guint64 b)
365 {
366         MONO_ARCH_SAVE_REGS;
367
368 #ifdef MONO_ARCH_NEED_DIV_CHECK
369         if (!b)
370                 mono_raise_exception (mono_get_exception_divide_by_zero ());
371 #endif
372         return a % b;
373 }
374
375 #endif
376
377 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
378
379 guint64 
380 mono_lshl (guint64 a, gint32 shamt)
381 {
382         guint64 res;
383
384         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
385         res = a << shamt;
386
387         /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
388
389         return res;
390 }
391
392 guint64 
393 mono_lshr_un (guint64 a, gint32 shamt)
394 {
395         guint64 res;
396
397         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
398         res = a >> shamt;
399
400         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
401
402         return res;
403 }
404
405 gint64 
406 mono_lshr (gint64 a, gint32 shamt)
407 {
408         gint64 res;
409
410         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
411         res = a >> shamt;
412
413         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
414
415         return res;
416 }
417
418 #endif
419
420 /**
421  * ves_array_element_address:
422  * @this: a pointer to the array object
423  *
424  * Returns: the address of an array element.
425  */
426 gpointer 
427 ves_array_element_address (MonoArray *this, ...)
428 {
429         MonoClass *class;
430         va_list ap;
431         int i, ind, esize, realidx;
432         gpointer ea;
433
434         MONO_ARCH_SAVE_REGS;
435
436         g_assert (this != NULL);
437
438         va_start(ap, this);
439
440         class = this->obj.vtable->klass;
441
442         g_assert (this->bounds != NULL);
443
444         esize = mono_array_element_size (class);
445         ind = va_arg(ap, int);
446         ind -= (int)this->bounds [0].lower_bound;
447         if ((guint32)ind >= (guint32)this->bounds [0].length)
448                 mono_raise_exception (mono_get_exception_index_out_of_range ());
449         for (i = 1; i < class->rank; i++) {
450                 realidx = va_arg(ap, int) - (int)this->bounds [i].lower_bound;
451                 if ((guint32)realidx >= (guint32)this->bounds [i].length)
452                         mono_raise_exception (mono_get_exception_index_out_of_range ());
453                 ind *= this->bounds [i].length;
454                 ind += realidx;
455         }
456         esize *= ind;
457
458         ea = (gpointer*)(gpointer)((char*)this->vector + esize);
459
460         va_end(ap);
461
462         return ea;
463 }
464
465 MonoArray *
466 mono_array_new_va (MonoMethod *cm, ...)
467 {
468         MonoDomain *domain = mono_domain_get ();
469         va_list ap;
470         guint32 *lengths;
471         guint32 *lower_bounds;
472         int pcount;
473         int rank;
474         int i, d;
475
476         MONO_ARCH_SAVE_REGS;
477
478         pcount = mono_method_signature (cm)->param_count;
479         rank = cm->klass->rank;
480
481         va_start (ap, cm);
482         
483         lengths = alloca (sizeof (guint32) * pcount);
484         for (i = 0; i < pcount; ++i)
485                 lengths [i] = d = va_arg(ap, int);
486
487         if (rank == pcount) {
488                 /* Only lengths provided. */
489                 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
490                         lower_bounds = alloca (sizeof (guint32) * rank);
491                         memset (lower_bounds, 0, sizeof (guint32) * rank);
492                 } else {
493                         lower_bounds = NULL;
494                 }
495         } else {
496                 g_assert (pcount == (rank * 2));
497                 /* lower bounds are first. */
498                 lower_bounds = lengths;
499                 lengths += rank;
500         }
501         va_end(ap);
502
503         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
504 }
505
506 gpointer
507 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
508 {
509         MonoVTable *vtable;
510         gpointer addr;
511         
512         MONO_ARCH_SAVE_REGS;
513
514         //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
515
516         mono_class_init (field->parent);
517
518         vtable = mono_class_vtable (domain, field->parent);
519         if (!vtable->initialized)
520                 mono_runtime_class_init (vtable);
521
522         //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
523
524         if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
525                 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
526         else
527                 addr = (char*)vtable->data + field->offset;
528         
529         return addr;
530 }
531
532 gpointer
533 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
534 {
535         MonoClass *handle_class;
536         gpointer res;
537
538         MONO_ARCH_SAVE_REGS;
539         res = mono_ldtoken (image, token, &handle_class, context);      
540         mono_class_init (handle_class);
541
542         return res;
543 }
544
545 guint64
546 mono_fconv_u8 (double v)
547 {
548         return (guint64)v;
549 }
550
551 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
552 gint64
553 mono_fconv_i8 (double v)
554 {
555         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
556         return (gint64)v;
557 }
558 #endif
559
560 guint32
561 mono_fconv_u4 (double v)
562 {
563         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
564         return (guint32)v;
565 }
566
567 #ifndef HAVE_TRUNC
568 /* Solaris doesn't have trunc */
569 #ifdef HAVE_AINTL
570 extern long double aintl (long double);
571 #define trunc aintl
572 #else
573 /* FIXME: This means we will never throw overflow exceptions */
574 #define trunc(v) res
575 #endif
576 #endif /* HAVE_TRUNC */
577
578 gint64
579 mono_fconv_ovf_i8 (double v)
580 {
581         gint64 res;
582
583         MONO_ARCH_SAVE_REGS;
584
585         res = (gint64)v;
586
587         if (isnan(v) || trunc (v) != res) {
588                 mono_raise_exception (mono_get_exception_overflow ());
589         }
590         return res;
591 }
592
593 guint64
594 mono_fconv_ovf_u8 (double v)
595 {
596         guint64 res;
597
598         MONO_ARCH_SAVE_REGS;
599     
600         res = (guint64)v;
601
602         if (isnan(v) || trunc (v) != res) {
603                 mono_raise_exception (mono_get_exception_overflow ());
604         }
605         return res;
606 }
607
608 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
609 double
610 mono_lconv_to_r8 (gint64 a)
611 {
612         return (double)a;
613 }
614 #endif
615
616 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
617 float
618 mono_lconv_to_r4 (gint64 a)
619 {
620         return (float)a;
621 }
622 #endif
623
624 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
625 double
626 mono_conv_to_r8_un (guint32 a)
627 {
628         return (double)a;
629 }
630 #endif
631
632 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
633 double
634 mono_lconv_to_r8_un (guint64 a)
635 {
636         return (double)a;
637 }
638 #endif
639
640 gpointer
641 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context, gpointer *this_arg)
642 {
643         MonoMethod *vmethod, *inflated;
644         gpointer addr;
645
646         if (obj == NULL)
647                 mono_raise_exception (mono_get_exception_null_reference ());
648         vmethod = mono_object_get_virtual_method (obj, method);
649
650         /* 'vmethod' is partially inflated.  All the blanks corresponding to the type parameters of the
651            declaring class have been inflated.  We still need to fully inflate the method parameters.
652
653            FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with 
654            the same context.
655         */
656         g_assert (!vmethod->klass->generic_container);
657         g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->inst->is_open);
658         g_assert (!context->gmethod || !context->gmethod->inst->is_open);
659         inflated = mono_class_inflate_generic_method (vmethod, context);
660         inflated = mono_get_inflated_method (inflated);
661         addr = mono_compile_method (inflated);
662
663         /* Since this is a virtual call, have to unbox vtypes */
664         if (obj->vtable->klass->valuetype)
665                 *this_arg = mono_object_unbox (obj);
666         else
667                 *this_arg = obj;
668
669         return addr;
670 }
671
672 MonoString*
673 mono_helper_ldstr (MonoImage *image, guint32 idx)
674 {
675         return mono_ldstr (mono_domain_get (), image, idx);
676 }
677
678 MonoString*
679 mono_helper_ldstr_mscorlib (guint32 idx)
680 {
681         return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
682 }
683
684 MonoObject*
685 mono_helper_newobj_mscorlib (guint32 idx)
686 {
687         MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
688         
689         g_assert (klass);
690
691         return mono_object_new (mono_domain_get (), klass);
692 }