2 * jit-icalls.c: internal calls used by the JIT
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2002 Ximian, Inc.
13 #include "jit-icalls.h"
16 mono_ldftn (MonoMethod *method)
22 addr = mono_create_jump_trampoline (mono_domain_get (), method, TRUE);
24 return mono_create_ftnptr (mono_domain_get (), addr);
28 * Same as mono_ldftn, but do not add a synchronized wrapper. Used in the
29 * synchronized wrappers to avoid infinite recursion.
32 mono_ldftn_nosync (MonoMethod *method)
38 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
40 return mono_create_ftnptr (mono_domain_get (), addr);
44 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
49 mono_raise_exception (mono_get_exception_null_reference ());
51 method = mono_object_get_virtual_method (obj, method);
53 return mono_ldftn (method);
57 mono_helper_stelem_ref (MonoArray *array, int index, MonoObject *val)
61 if (index >= array->max_length)
62 mono_raise_exception (mono_get_exception_index_out_of_range ());
64 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
65 mono_raise_exception (mono_get_exception_array_type_mismatch ());
67 mono_array_set (array, gpointer, index, val);
71 mono_helper_stelem_ref_check (MonoArray *array, MonoObject *val)
75 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
76 mono_raise_exception (mono_get_exception_array_type_mismatch ());
79 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
82 mono_llmult (gint64 a, gint64 b)
84 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
89 mono_llmult_ovf_un (guint64 a, guint64 b)
99 // fixme: this is incredible slow
102 goto raise_exception;
104 res = (guint64)al * (guint64)bl;
106 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
109 goto raise_exception;
111 res += ((guint64)t1) << 32;
116 mono_raise_exception (mono_get_exception_overflow ());
121 mono_llmult_ovf (gint64 a, gint64 b)
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)
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.
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
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
154 if (((guint32)ah == 0x80000000) && (al == 0)) {
155 /* This has no two's complement */
161 goto raise_exception;
164 /* flip the bits and add 1 */
175 if (((guint32)bh == 0x80000000) && (bl == 0)) {
176 /* This has no two's complement */
182 goto raise_exception;
185 /* flip the bits and add 1 */
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 */
200 goto raise_exception;
201 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
202 goto raise_exception;
204 /* do the AlBl term first */
205 t1 = (gint64)al * (gint64)bl;
209 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
210 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
211 /* check for overflow */
213 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
214 goto raise_exception;
219 goto raise_exception;
227 mono_raise_exception (mono_get_exception_overflow ());
231 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
234 mono_idiv (gint32 a, gint32 b)
238 #ifdef MONO_ARCH_NEED_DIV_CHECK
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 ());
248 mono_idiv_un (guint32 a, guint32 b)
252 #ifdef MONO_ARCH_NEED_DIV_CHECK
254 mono_raise_exception (mono_get_exception_divide_by_zero ());
260 mono_irem (gint32 a, gint32 b)
264 #ifdef MONO_ARCH_NEED_DIV_CHECK
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 ());
275 mono_irem_un (guint32 a, guint32 b)
279 #ifdef MONO_ARCH_NEED_DIV_CHECK
281 mono_raise_exception (mono_get_exception_divide_by_zero ());
288 #ifdef MONO_ARCH_EMULATE_MUL_DIV
291 mono_imul (gint32 a, gint32 b)
299 mono_imul_ovf (gint32 a, gint32 b)
305 res = (gint64)a * (gint64)b;
307 if ((res > 0x7fffffffL) || (res < -2147483648))
308 mono_raise_exception (mono_get_exception_overflow ());
314 mono_imul_ovf_un (guint32 a, guint32 b)
320 res = (guint64)a * (guint64)b;
323 mono_raise_exception (mono_get_exception_overflow ());
329 mono_fdiv (double a, double b)
338 mono_lldiv (gint64 a, gint64 b)
342 #ifdef MONO_ARCH_NEED_DIV_CHECK
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 ());
352 mono_llrem (gint64 a, gint64 b)
356 #ifdef MONO_ARCH_NEED_DIV_CHECK
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 ());
366 mono_lldiv_un (guint64 a, guint64 b)
370 #ifdef MONO_ARCH_NEED_DIV_CHECK
372 mono_raise_exception (mono_get_exception_divide_by_zero ());
378 mono_llrem_un (guint64 a, guint64 b)
382 #ifdef MONO_ARCH_NEED_DIV_CHECK
384 mono_raise_exception (mono_get_exception_divide_by_zero ());
391 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
394 mono_lshl (guint64 a, gint32 shamt)
398 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
401 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
407 mono_lshr_un (guint64 a, gint32 shamt)
411 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
414 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
420 mono_lshr (gint64 a, gint32 shamt)
424 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
427 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
435 * ves_array_element_address:
436 * @this: a pointer to the array object
438 * Returns: the address of an array element.
441 ves_array_element_address (MonoArray *this, ...)
445 int i, ind, esize, realidx;
450 g_assert (this != NULL);
454 class = this->obj.vtable->klass;
456 g_assert (this->bounds != NULL);
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;
472 ea = (gpointer*)(gpointer)((char*)this->vector + esize);
480 mono_array_new_va (MonoMethod *cm, ...)
482 MonoDomain *domain = mono_domain_get ();
485 guint32 *lower_bounds;
492 pcount = mono_method_signature (cm)->param_count;
493 rank = cm->klass->rank;
497 lengths = alloca (sizeof (guint32) * pcount);
498 for (i = 0; i < pcount; ++i)
499 lengths [i] = d = va_arg(ap, int);
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);
510 g_assert (pcount == (rank * 2));
511 /* lower bounds are first. */
512 lower_bounds = lengths;
517 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
521 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
528 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
530 mono_class_init (field->parent);
532 vtable = mono_class_vtable (domain, field->parent);
533 if (!vtable->initialized)
534 mono_runtime_class_init (vtable);
536 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
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));
541 addr = (char*)vtable->data + field->offset;
547 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
549 MonoClass *handle_class;
553 res = mono_ldtoken (image, token, &handle_class, context);
554 mono_class_init (handle_class);
560 mono_fconv_u8 (double v)
565 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
567 mono_fconv_i8 (double v)
569 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
575 mono_fconv_u4 (double v)
577 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
582 /* Solaris doesn't have trunc */
584 extern long double aintl (long double);
587 /* FIXME: This means we will never throw overflow exceptions */
590 #endif /* HAVE_TRUNC */
593 mono_fconv_ovf_i8 (double v)
601 if (isnan(v) || trunc (v) != res) {
602 mono_raise_exception (mono_get_exception_overflow ());
608 mono_fconv_ovf_u8 (double v)
616 if (isnan(v) || trunc (v) != res) {
617 mono_raise_exception (mono_get_exception_overflow ());
622 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
624 mono_lconv_to_r8 (gint64 a)
630 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
632 mono_lconv_to_r4 (gint64 a)
638 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
640 mono_conv_to_r8_un (guint32 a)
646 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
648 mono_lconv_to_r8_un (guint64 a)
655 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context)
657 MonoMethod *vmethod, *inflated;
661 mono_raise_exception (mono_get_exception_null_reference ());
662 vmethod = mono_object_get_virtual_method (obj, method);
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.
667 FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with
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);
681 mono_helper_ldstr (MonoImage *image, guint32 idx)
683 return mono_ldstr (mono_domain_get (), image, idx);
687 mono_helper_ldstr_mscorlib (guint32 idx)
689 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
693 mono_helper_newobj_mscorlib (guint32 idx)
695 MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
699 return mono_object_new (mono_domain_get (), klass);