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_check (MonoArray *array, MonoObject *val)
61 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
62 mono_raise_exception (mono_get_exception_array_type_mismatch ());
65 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
68 mono_llmult (gint64 a, gint64 b)
70 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
75 mono_llmult_ovf_un (guint64 a, guint64 b)
85 // fixme: this is incredible slow
90 res = (guint64)al * (guint64)bl;
92 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
97 res += ((guint64)t1) << 32;
102 mono_raise_exception (mono_get_exception_overflow ());
107 mono_llmult_ovf (gint64 a, gint64 b)
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)
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.
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
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
140 if (((guint32)ah == 0x80000000) && (al == 0)) {
141 /* This has no two's complement */
147 goto raise_exception;
150 /* flip the bits and add 1 */
161 if (((guint32)bh == 0x80000000) && (bl == 0)) {
162 /* This has no two's complement */
168 goto raise_exception;
171 /* flip the bits and add 1 */
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 */
186 goto raise_exception;
187 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
188 goto raise_exception;
190 /* do the AlBl term first */
191 t1 = (gint64)al * (gint64)bl;
195 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
196 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
197 /* check for overflow */
199 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
200 goto raise_exception;
205 goto raise_exception;
213 mono_raise_exception (mono_get_exception_overflow ());
217 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
220 mono_idiv (gint32 a, gint32 b)
224 #ifdef MONO_ARCH_NEED_DIV_CHECK
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 ());
234 mono_idiv_un (guint32 a, guint32 b)
238 #ifdef MONO_ARCH_NEED_DIV_CHECK
240 mono_raise_exception (mono_get_exception_divide_by_zero ());
246 mono_irem (gint32 a, gint32 b)
250 #ifdef MONO_ARCH_NEED_DIV_CHECK
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 ());
261 mono_irem_un (guint32 a, guint32 b)
265 #ifdef MONO_ARCH_NEED_DIV_CHECK
267 mono_raise_exception (mono_get_exception_divide_by_zero ());
274 #ifdef MONO_ARCH_EMULATE_MUL_DIV
277 mono_imul (gint32 a, gint32 b)
285 mono_imul_ovf (gint32 a, gint32 b)
291 res = (gint64)a * (gint64)b;
293 if ((res > 0x7fffffffL) || (res < -2147483648))
294 mono_raise_exception (mono_get_exception_overflow ());
300 mono_imul_ovf_un (guint32 a, guint32 b)
306 res = (guint64)a * (guint64)b;
309 mono_raise_exception (mono_get_exception_overflow ());
315 mono_fdiv (double a, double b)
324 mono_lldiv (gint64 a, gint64 b)
328 #ifdef MONO_ARCH_NEED_DIV_CHECK
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 ());
338 mono_llrem (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_lldiv_un (guint64 a, guint64 b)
356 #ifdef MONO_ARCH_NEED_DIV_CHECK
358 mono_raise_exception (mono_get_exception_divide_by_zero ());
364 mono_llrem_un (guint64 a, guint64 b)
368 #ifdef MONO_ARCH_NEED_DIV_CHECK
370 mono_raise_exception (mono_get_exception_divide_by_zero ());
377 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
380 mono_lshl (guint64 a, gint32 shamt)
384 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
387 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
393 mono_lshr_un (guint64 a, gint32 shamt)
397 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
400 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
406 mono_lshr (gint64 a, gint32 shamt)
410 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
413 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
421 * ves_array_element_address:
422 * @this: a pointer to the array object
424 * Returns: the address of an array element.
427 ves_array_element_address (MonoArray *this, ...)
431 int i, ind, esize, realidx;
436 g_assert (this != NULL);
440 class = this->obj.vtable->klass;
442 g_assert (this->bounds != NULL);
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;
458 ea = (gpointer*)(gpointer)((char*)this->vector + esize);
466 mono_array_new_va (MonoMethod *cm, ...)
468 MonoDomain *domain = mono_domain_get ();
471 guint32 *lower_bounds;
478 pcount = mono_method_signature (cm)->param_count;
479 rank = cm->klass->rank;
483 lengths = alloca (sizeof (guint32) * pcount);
484 for (i = 0; i < pcount; ++i)
485 lengths [i] = d = va_arg(ap, int);
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);
496 g_assert (pcount == (rank * 2));
497 /* lower bounds are first. */
498 lower_bounds = lengths;
503 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
507 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
514 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
516 mono_class_init (field->parent);
518 vtable = mono_class_vtable (domain, field->parent);
519 if (!vtable->initialized)
520 mono_runtime_class_init (vtable);
522 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
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));
527 addr = (char*)vtable->data + field->offset;
533 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
535 MonoClass *handle_class;
539 res = mono_ldtoken (image, token, &handle_class, context);
540 mono_class_init (handle_class);
546 mono_fconv_u8 (double v)
551 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
553 mono_fconv_i8 (double v)
555 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
561 mono_fconv_u4 (double v)
563 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
568 /* Solaris doesn't have trunc */
570 extern long double aintl (long double);
573 /* FIXME: This means we will never throw overflow exceptions */
576 #endif /* HAVE_TRUNC */
579 mono_fconv_ovf_i8 (double v)
587 if (isnan(v) || trunc (v) != res) {
588 mono_raise_exception (mono_get_exception_overflow ());
594 mono_fconv_ovf_u8 (double v)
602 if (isnan(v) || trunc (v) != res) {
603 mono_raise_exception (mono_get_exception_overflow ());
608 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
610 mono_lconv_to_r8 (gint64 a)
616 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
618 mono_lconv_to_r4 (gint64 a)
624 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
626 mono_conv_to_r8_un (guint32 a)
632 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
634 mono_lconv_to_r8_un (guint64 a)
641 mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context, gpointer *this_arg)
643 MonoMethod *vmethod, *inflated;
647 mono_raise_exception (mono_get_exception_null_reference ());
648 vmethod = mono_object_get_virtual_method (obj, method);
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.
653 FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with
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);
663 /* Since this is a virtual call, have to unbox vtypes */
664 if (obj->vtable->klass->valuetype)
665 *this_arg = mono_object_unbox (obj);
673 mono_helper_ldstr (MonoImage *image, guint32 idx)
675 return mono_ldstr (mono_domain_get (), image, idx);
679 mono_helper_ldstr_mscorlib (guint32 idx)
681 return mono_ldstr (mono_domain_get (), mono_defaults.corlib, idx);
685 mono_helper_newobj_mscorlib (guint32 idx)
687 MonoClass *klass = mono_class_get (mono_defaults.corlib, MONO_TOKEN_TYPE_DEF | idx);
691 return mono_object_new (mono_domain_get (), klass);