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)
46 method = mono_object_get_virtual_method (obj, method);
48 return mono_ldftn (method);
52 helper_initobj (void *addr, int size)
56 memset (addr, 0, size);
60 helper_memcpy (void *addr, void *src, int size)
64 memcpy (addr, src, size);
68 helper_memset (void *addr, int val, int size)
72 memset (addr, val, size);
76 helper_stelem_ref (MonoArray *array, int index, MonoObject *val)
80 if (index >= array->max_length)
81 mono_raise_exception (mono_get_exception_index_out_of_range ());
83 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
84 mono_raise_exception (mono_get_exception_array_type_mismatch ());
86 mono_array_set (array, gpointer, index, val);
90 helper_stelem_ref_check (MonoArray *array, MonoObject *val)
94 if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
95 mono_raise_exception (mono_get_exception_array_type_mismatch ());
99 mono_llmult (gint64 a, gint64 b)
101 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
106 mono_llmult_ovf_un (guint64 a, guint64 b)
109 guint32 ah = a >> 32;
111 guint32 bh = b >> 32;
116 // fixme: this is incredible slow
119 goto raise_exception;
121 res = (guint64)al * (guint64)bl;
123 t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
126 goto raise_exception;
128 res += ((guint64)t1) << 32;
133 mono_raise_exception (mono_get_exception_overflow ());
139 mono_llmult_ovf (gint64 a, gint64 b)
146 Use Karatsuba algorithm where:
147 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
148 where Ah is the "high half" (most significant 32 bits) of a and
149 where Al is the "low half" (least significant 32 bits) of a and
150 where Bh is the "high half" of b and Bl is the "low half" and
151 where R is the Radix or "size of the half" (in our case 32 bits)
153 Note, for the product of two 64 bit numbers to fit into a 64
154 result, ah and/or bh must be 0. This will save us from doing
155 the AhBh term at all.
157 Also note that we refactor so that we don't overflow 64 bits with
158 intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
166 /* need to work with absoulte values, so find out what the
167 resulting sign will be and convert any negative numbers
168 from two's complement
172 if (((guint32)ah == 0x80000000) && (al == 0)) {
173 /* This has no two's complement */
179 goto raise_exception;
182 /* flip the bits and add 1 */
193 if (((guint32)bh == 0x80000000) && (bl == 0)) {
194 /* This has no two's complement */
200 goto raise_exception;
203 /* flip the bits and add 1 */
213 /* we overflow for sure if both upper halves are greater
214 than zero because we would need to shift their
215 product 64 bits to the left and that will not fit
216 in a 64 bit result */
218 goto raise_exception;
220 /* do the AlBl term first */
221 t1 = (gint64)al * (gint64)bl;
225 /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
226 t1 += (gint64)(ah - al) * (gint64)(bl - bh);
228 /* check for overflow */
229 if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
230 goto raise_exception;
235 goto raise_exception;
243 mono_raise_exception (mono_get_exception_overflow ());
248 mono_lldiv (gint64 a, gint64 b)
252 #ifdef MONO_ARCH_NEED_DIV_CHECK
254 mono_raise_exception (mono_get_exception_divide_by_zero ());
255 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
256 mono_raise_exception (mono_get_exception_arithmetic ());
262 mono_llrem (gint64 a, gint64 b)
266 #ifdef MONO_ARCH_NEED_DIV_CHECK
268 mono_raise_exception (mono_get_exception_divide_by_zero ());
269 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
270 mono_raise_exception (mono_get_exception_arithmetic ());
276 mono_lldiv_un (guint64 a, guint64 b)
280 #ifdef MONO_ARCH_NEED_DIV_CHECK
282 mono_raise_exception (mono_get_exception_divide_by_zero ());
288 mono_llrem_un (guint64 a, guint64 b)
292 #ifdef MONO_ARCH_NEED_DIV_CHECK
294 mono_raise_exception (mono_get_exception_divide_by_zero ());
299 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
302 mono_lshl (guint64 a, gint32 shamt)
306 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
309 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
315 mono_lshr_un (guint64 a, gint32 shamt)
319 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
322 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
328 mono_lshr (gint64 a, gint32 shamt)
332 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
335 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
343 * ves_array_element_address:
344 * @this: a pointer to the array object
346 * Returns: the address of an array element.
349 ves_array_element_address (MonoArray *this, ...)
353 int i, ind, esize, realidx;
358 g_assert (this != NULL);
362 class = this->obj.vtable->klass;
364 g_assert (this->bounds != NULL);
366 esize = mono_array_element_size (class);
367 ind = va_arg(ap, int);
368 ind -= (int)this->bounds [0].lower_bound;
369 if ((guint32)ind >= (guint32)this->bounds [0].length)
370 mono_raise_exception (mono_get_exception_index_out_of_range ());
371 for (i = 1; i < class->rank; i++) {
372 realidx = va_arg(ap, int) - (int)this->bounds [i].lower_bound;
373 if ((guint32)realidx >= (guint32)this->bounds [i].length)
374 mono_raise_exception (mono_get_exception_index_out_of_range ());
375 ind *= this->bounds [i].length;
380 ea = (gpointer*)((char*)this->vector + esize);
388 mono_array_new_va (MonoMethod *cm, ...)
390 MonoDomain *domain = mono_domain_get ();
393 guint32 *lower_bounds;
400 pcount = cm->signature->param_count;
401 rank = cm->klass->rank;
405 lengths = alloca (sizeof (guint32) * pcount);
406 for (i = 0; i < pcount; ++i)
407 lengths [i] = d = va_arg(ap, int);
409 if (rank == pcount) {
410 /* Only lengths provided. */
413 g_assert (pcount == (rank * 2));
414 /* lower bounds are first. */
415 lower_bounds = lengths;
420 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
424 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
431 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
433 mono_class_init (field->parent);
435 vtable = mono_class_vtable (domain, field->parent);
436 if (!vtable->initialized)
437 mono_runtime_class_init (vtable);
439 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
441 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
442 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
444 addr = (char*)vtable->data + field->offset;
450 mono_ldtoken_wrapper (MonoImage *image, int token)
452 MonoClass *handle_class;
456 res = mono_ldtoken (image, token, &handle_class, NULL);
457 mono_class_init (handle_class);
463 mono_fconv_u8 (double v)
468 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
470 mono_fconv_i8 (double v)
472 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
478 mono_fconv_u4 (double v)
480 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
485 /* Solaris doesn't have trunc */
487 extern long double aintl (long double);
490 /* FIXME: This means we will never throw overflow exceptions */
493 #endif /* HAVE_TRUNC */
496 mono_fconv_ovf_i8 (double v)
504 if (isnan(v) || trunc (v) != res) {
505 mono_raise_exception (mono_get_exception_overflow ());
511 mono_fconv_ovf_u8 (double v)
519 if (isnan(v) || trunc (v) != res) {
520 mono_raise_exception (mono_get_exception_overflow ());
525 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
527 mono_lconv_to_r8 (gint64 a)
533 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
535 mono_lconv_to_r4 (gint64 a)
541 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
543 mono_conv_to_r8_un (guint32 a)
549 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
551 mono_lconv_to_r8_un (guint64 a)