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.
14 mono_ldftn (MonoMethod *method)
20 addr = mono_create_jump_trampoline (mono_domain_get (), method, TRUE);
26 * Same as mono_ldftn, but do not add a synchronized wrapper. Used in the
27 * synchronized wrappers to avoid infinite recursion.
30 mono_ldftn_nosync (MonoMethod *method)
36 addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE);
42 mono_ldvirtfn (MonoObject *obj, MonoMethod *method)
47 mono_raise_exception (mono_get_exception_null_reference ());
49 method = mono_object_get_virtual_method (obj, method);
51 return mono_ldftn (method);
55 helper_stelem_ref (MonoArray *array, int index, MonoObject *val)
59 if (index >= array->max_length)
60 mono_raise_exception (mono_get_exception_index_out_of_range ());
62 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
63 mono_raise_exception (mono_get_exception_array_type_mismatch ());
65 mono_array_set (array, gpointer, index, val);
69 helper_stelem_ref_check (MonoArray *array, MonoObject *val)
73 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
74 mono_raise_exception (mono_get_exception_array_type_mismatch ());
77 #ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
80 mono_llmult (gint64 a, gint64 b)
82 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
87 mono_llmult_ovf_un (guint64 a, guint64 b)
97 // fixme: this is incredible slow
100 goto raise_exception;
102 res = (guint64)al * (guint64)bl;
104 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
107 goto raise_exception;
109 res += ((guint64)t1) << 32;
114 mono_raise_exception (mono_get_exception_overflow ());
119 mono_llmult_ovf (gint64 a, gint64 b)
126 Use Karatsuba algorithm where:
127 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
128 where Ah is the "high half" (most significant 32 bits) of a and
129 where Al is the "low half" (least significant 32 bits) of a and
130 where Bh is the "high half" of b and Bl is the "low half" and
131 where R is the Radix or "size of the half" (in our case 32 bits)
133 Note, for the product of two 64 bit numbers to fit into a 64
134 result, ah and/or bh must be 0. This will save us from doing
135 the AhBh term at all.
137 Also note that we refactor so that we don't overflow 64 bits with
138 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
146 /* need to work with absoulte values, so find out what the
147 resulting sign will be and convert any negative numbers
148 from two's complement
152 if (((guint32)ah == 0x80000000) && (al == 0)) {
153 /* This has no two's complement */
159 goto raise_exception;
162 /* flip the bits and add 1 */
173 if (((guint32)bh == 0x80000000) && (bl == 0)) {
174 /* This has no two's complement */
180 goto raise_exception;
183 /* flip the bits and add 1 */
193 /* we overflow for sure if both upper halves are greater
194 than zero because we would need to shift their
195 product 64 bits to the left and that will not fit
196 in a 64 bit result */
198 goto raise_exception;
199 if ((gint64)((gint64)ah * (gint64)bl) > (gint64)0x80000000 || (gint64)((gint64)al * (gint64)bh) > (gint64)0x80000000)
200 goto raise_exception;
202 /* do the AlBl term first */
203 t1 = (gint64)al * (gint64)bl;
207 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
208 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
209 /* check for overflow */
211 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
212 goto raise_exception;
217 goto raise_exception;
225 mono_raise_exception (mono_get_exception_overflow ());
229 #ifdef MONO_ARCH_EMULATE_MUL_DIV
232 mono_imul (gint32 a, gint32 b)
240 mono_idiv (gint32 a, gint32 b)
244 #ifdef MONO_ARCH_NEED_DIV_CHECK
246 mono_raise_exception (mono_get_exception_divide_by_zero ());
247 else if (b == -1 && a == (0x80000000))
248 mono_raise_exception (mono_get_exception_arithmetic ());
254 mono_idiv_un (guint32 a, guint32 b)
258 #ifdef MONO_ARCH_NEED_DIV_CHECK
260 mono_raise_exception (mono_get_exception_divide_by_zero ());
266 mono_irem (gint32 a, gint32 b)
270 #ifdef MONO_ARCH_NEED_DIV_CHECK
272 mono_raise_exception (mono_get_exception_divide_by_zero ());
273 else if (b == -1 && a == (0x80000000))
274 mono_raise_exception (mono_get_exception_arithmetic ());
281 mono_irem_un (guint32 a, guint32 b)
285 #ifdef MONO_ARCH_NEED_DIV_CHECK
287 mono_raise_exception (mono_get_exception_divide_by_zero ());
293 mono_imul_ovf (gint32 a, gint32 b)
299 res = (gint64)a * (gint64)b;
301 if ((res > 0x7fffffffL) || (res < -2147483648))
302 mono_raise_exception (mono_get_exception_overflow ());
308 mono_imul_ovf_un (guint32 a, guint32 b)
314 res = (guint64)a * (guint64)b;
317 mono_raise_exception (mono_get_exception_overflow ());
323 mono_fdiv (double a, double b)
332 mono_lldiv (gint64 a, gint64 b)
336 #ifdef MONO_ARCH_NEED_DIV_CHECK
338 mono_raise_exception (mono_get_exception_divide_by_zero ());
339 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
340 mono_raise_exception (mono_get_exception_arithmetic ());
346 mono_llrem (gint64 a, gint64 b)
350 #ifdef MONO_ARCH_NEED_DIV_CHECK
352 mono_raise_exception (mono_get_exception_divide_by_zero ());
353 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
354 mono_raise_exception (mono_get_exception_arithmetic ());
360 mono_lldiv_un (guint64 a, guint64 b)
364 #ifdef MONO_ARCH_NEED_DIV_CHECK
366 mono_raise_exception (mono_get_exception_divide_by_zero ());
372 mono_llrem_un (guint64 a, guint64 b)
376 #ifdef MONO_ARCH_NEED_DIV_CHECK
378 mono_raise_exception (mono_get_exception_divide_by_zero ());
385 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
388 mono_lshl (guint64 a, gint32 shamt)
392 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
395 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
401 mono_lshr_un (guint64 a, gint32 shamt)
405 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
408 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
414 mono_lshr (gint64 a, gint32 shamt)
418 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
421 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
429 * ves_array_element_address:
430 * @this: a pointer to the array object
432 * Returns: the address of an array element.
435 ves_array_element_address (MonoArray *this, ...)
439 int i, ind, esize, realidx;
444 g_assert (this != NULL);
448 class = this->obj.vtable->klass;
450 g_assert (this->bounds != NULL);
452 esize = mono_array_element_size (class);
453 ind = va_arg(ap, int);
454 ind -= (int)this->bounds [0].lower_bound;
455 if ((guint32)ind >= (guint32)this->bounds [0].length)
456 mono_raise_exception (mono_get_exception_index_out_of_range ());
457 for (i = 1; i < class->rank; i++) {
458 realidx = va_arg(ap, int) - (int)this->bounds [i].lower_bound;
459 if ((guint32)realidx >= (guint32)this->bounds [i].length)
460 mono_raise_exception (mono_get_exception_index_out_of_range ());
461 ind *= this->bounds [i].length;
466 ea = (gpointer*)(gpointer)((char*)this->vector + esize);
474 mono_array_new_va (MonoMethod *cm, ...)
476 MonoDomain *domain = mono_domain_get ();
479 guint32 *lower_bounds;
486 pcount = mono_method_signature (cm)->param_count;
487 rank = cm->klass->rank;
491 lengths = alloca (sizeof (guint32) * pcount);
492 for (i = 0; i < pcount; ++i)
493 lengths [i] = d = va_arg(ap, int);
495 if (rank == pcount) {
496 /* Only lengths provided. */
499 g_assert (pcount == (rank * 2));
500 /* lower bounds are first. */
501 lower_bounds = lengths;
506 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
510 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
517 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
519 mono_class_init (field->parent);
521 vtable = mono_class_vtable (domain, field->parent);
522 if (!vtable->initialized)
523 mono_runtime_class_init (vtable);
525 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
527 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
528 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
530 addr = (char*)vtable->data + field->offset;
536 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
538 MonoClass *handle_class;
542 res = mono_ldtoken (image, token, &handle_class, context);
543 mono_class_init (handle_class);
549 mono_fconv_u8 (double v)
554 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
556 mono_fconv_i8 (double v)
558 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
564 mono_fconv_u4 (double v)
566 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
571 /* Solaris doesn't have trunc */
573 extern long double aintl (long double);
576 /* FIXME: This means we will never throw overflow exceptions */
579 #endif /* HAVE_TRUNC */
582 mono_fconv_ovf_i8 (double v)
590 if (isnan(v) || trunc (v) != res) {
591 mono_raise_exception (mono_get_exception_overflow ());
597 mono_fconv_ovf_u8 (double v)
605 if (isnan(v) || trunc (v) != res) {
606 mono_raise_exception (mono_get_exception_overflow ());
611 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
613 mono_lconv_to_r8 (gint64 a)
619 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
621 mono_lconv_to_r4 (gint64 a)
627 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
629 mono_conv_to_r8_un (guint32 a)
635 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
637 mono_lconv_to_r8_un (guint64 a)
644 helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context)
646 MonoMethod *vmethod, *inflated;
649 vmethod = mono_object_get_virtual_method (obj, method);
650 inflated = mono_class_inflate_generic_method (vmethod, context);
651 inflated = mono_get_inflated_method (inflated);
652 addr = mono_compile_method (inflated);