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);
22 return mono_create_ftnptr (mono_domain_get (), addr);
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);
38 return mono_create_ftnptr (mono_domain_get (), addr);
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 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
232 mono_idiv (gint32 a, gint32 b)
236 #ifdef MONO_ARCH_NEED_DIV_CHECK
238 mono_raise_exception (mono_get_exception_divide_by_zero ());
239 else if (b == -1 && a == (0x80000000))
240 mono_raise_exception (mono_get_exception_arithmetic ());
246 mono_idiv_un (guint32 a, guint32 b)
250 #ifdef MONO_ARCH_NEED_DIV_CHECK
252 mono_raise_exception (mono_get_exception_divide_by_zero ());
258 mono_irem (gint32 a, gint32 b)
262 #ifdef MONO_ARCH_NEED_DIV_CHECK
264 mono_raise_exception (mono_get_exception_divide_by_zero ());
265 else if (b == -1 && a == (0x80000000))
266 mono_raise_exception (mono_get_exception_arithmetic ());
273 mono_irem_un (guint32 a, guint32 b)
277 #ifdef MONO_ARCH_NEED_DIV_CHECK
279 mono_raise_exception (mono_get_exception_divide_by_zero ());
286 #ifdef MONO_ARCH_EMULATE_MUL_DIV
289 mono_imul (gint32 a, gint32 b)
297 mono_imul_ovf (gint32 a, gint32 b)
303 res = (gint64)a * (gint64)b;
305 if ((res > 0x7fffffffL) || (res < -2147483648))
306 mono_raise_exception (mono_get_exception_overflow ());
312 mono_imul_ovf_un (guint32 a, guint32 b)
318 res = (guint64)a * (guint64)b;
321 mono_raise_exception (mono_get_exception_overflow ());
327 mono_fdiv (double a, double b)
336 mono_lldiv (gint64 a, gint64 b)
340 #ifdef MONO_ARCH_NEED_DIV_CHECK
342 mono_raise_exception (mono_get_exception_divide_by_zero ());
343 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
344 mono_raise_exception (mono_get_exception_arithmetic ());
350 mono_llrem (gint64 a, gint64 b)
354 #ifdef MONO_ARCH_NEED_DIV_CHECK
356 mono_raise_exception (mono_get_exception_divide_by_zero ());
357 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
358 mono_raise_exception (mono_get_exception_arithmetic ());
364 mono_lldiv_un (guint64 a, guint64 b)
368 #ifdef MONO_ARCH_NEED_DIV_CHECK
370 mono_raise_exception (mono_get_exception_divide_by_zero ());
376 mono_llrem_un (guint64 a, guint64 b)
380 #ifdef MONO_ARCH_NEED_DIV_CHECK
382 mono_raise_exception (mono_get_exception_divide_by_zero ());
389 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
392 mono_lshl (guint64 a, gint32 shamt)
396 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
399 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
405 mono_lshr_un (guint64 a, gint32 shamt)
409 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
412 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
418 mono_lshr (gint64 a, gint32 shamt)
422 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
425 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
433 * ves_array_element_address:
434 * @this: a pointer to the array object
436 * Returns: the address of an array element.
439 ves_array_element_address (MonoArray *this, ...)
443 int i, ind, esize, realidx;
448 g_assert (this != NULL);
452 class = this->obj.vtable->klass;
454 g_assert (this->bounds != NULL);
456 esize = mono_array_element_size (class);
457 ind = va_arg(ap, int);
458 ind -= (int)this->bounds [0].lower_bound;
459 if ((guint32)ind >= (guint32)this->bounds [0].length)
460 mono_raise_exception (mono_get_exception_index_out_of_range ());
461 for (i = 1; i < class->rank; i++) {
462 realidx = va_arg(ap, int) - (int)this->bounds [i].lower_bound;
463 if ((guint32)realidx >= (guint32)this->bounds [i].length)
464 mono_raise_exception (mono_get_exception_index_out_of_range ());
465 ind *= this->bounds [i].length;
470 ea = (gpointer*)(gpointer)((char*)this->vector + esize);
478 mono_array_new_va (MonoMethod *cm, ...)
480 MonoDomain *domain = mono_domain_get ();
483 guint32 *lower_bounds;
490 pcount = mono_method_signature (cm)->param_count;
491 rank = cm->klass->rank;
495 lengths = alloca (sizeof (guint32) * pcount);
496 for (i = 0; i < pcount; ++i)
497 lengths [i] = d = va_arg(ap, int);
499 if (rank == pcount) {
500 /* Only lengths provided. */
501 if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) {
502 lower_bounds = alloca (sizeof (guint32) * rank);
503 memset (lower_bounds, 0, sizeof (guint32) * rank);
508 g_assert (pcount == (rank * 2));
509 /* lower bounds are first. */
510 lower_bounds = lengths;
515 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
519 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
526 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
528 mono_class_init (field->parent);
530 vtable = mono_class_vtable (domain, field->parent);
531 if (!vtable->initialized)
532 mono_runtime_class_init (vtable);
534 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
536 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
537 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
539 addr = (char*)vtable->data + field->offset;
545 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
547 MonoClass *handle_class;
551 res = mono_ldtoken (image, token, &handle_class, context);
552 mono_class_init (handle_class);
558 mono_fconv_u8 (double v)
563 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
565 mono_fconv_i8 (double v)
567 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
573 mono_fconv_u4 (double v)
575 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
580 /* Solaris doesn't have trunc */
582 extern long double aintl (long double);
585 /* FIXME: This means we will never throw overflow exceptions */
588 #endif /* HAVE_TRUNC */
591 mono_fconv_ovf_i8 (double v)
599 if (isnan(v) || trunc (v) != res) {
600 mono_raise_exception (mono_get_exception_overflow ());
606 mono_fconv_ovf_u8 (double v)
614 if (isnan(v) || trunc (v) != res) {
615 mono_raise_exception (mono_get_exception_overflow ());
620 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
622 mono_lconv_to_r8 (gint64 a)
628 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
630 mono_lconv_to_r4 (gint64 a)
636 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
638 mono_conv_to_r8_un (guint32 a)
644 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
646 mono_lconv_to_r8_un (guint64 a)
653 helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context)
655 MonoMethod *vmethod, *inflated;
658 vmethod = mono_object_get_virtual_method (obj, method);
659 inflated = mono_class_inflate_generic_method (vmethod, context);
660 inflated = mono_get_inflated_method (inflated);
661 addr = mono_compile_method (inflated);
667 helper_ldstr (MonoImage *image, guint32 idx)
669 return mono_ldstr (mono_domain_get (), image, idx);