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 ());
230 mono_lldiv (gint64 a, gint64 b)
234 #ifdef MONO_ARCH_NEED_DIV_CHECK
236 mono_raise_exception (mono_get_exception_divide_by_zero ());
237 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
238 mono_raise_exception (mono_get_exception_arithmetic ());
244 mono_llrem (gint64 a, gint64 b)
248 #ifdef MONO_ARCH_NEED_DIV_CHECK
250 mono_raise_exception (mono_get_exception_divide_by_zero ());
251 else if (b == -1 && a == (-9223372036854775807LL - 1LL))
252 mono_raise_exception (mono_get_exception_arithmetic ());
258 mono_lldiv_un (guint64 a, guint64 b)
262 #ifdef MONO_ARCH_NEED_DIV_CHECK
264 mono_raise_exception (mono_get_exception_divide_by_zero ());
270 mono_llrem_un (guint64 a, guint64 b)
274 #ifdef MONO_ARCH_NEED_DIV_CHECK
276 mono_raise_exception (mono_get_exception_divide_by_zero ());
283 #ifndef MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
286 mono_lshl (guint64 a, gint32 shamt)
290 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
293 /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
299 mono_lshr_un (guint64 a, gint32 shamt)
303 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
306 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
312 mono_lshr (gint64 a, gint32 shamt)
316 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
319 /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
327 * ves_array_element_address:
328 * @this: a pointer to the array object
330 * Returns: the address of an array element.
333 ves_array_element_address (MonoArray *this, ...)
337 int i, ind, esize, realidx;
342 g_assert (this != NULL);
346 class = this->obj.vtable->klass;
348 g_assert (this->bounds != NULL);
350 esize = mono_array_element_size (class);
351 ind = va_arg(ap, int);
352 ind -= (int)this->bounds [0].lower_bound;
353 if ((guint32)ind >= (guint32)this->bounds [0].length)
354 mono_raise_exception (mono_get_exception_index_out_of_range ());
355 for (i = 1; i < class->rank; i++) {
356 realidx = va_arg(ap, int) - (int)this->bounds [i].lower_bound;
357 if ((guint32)realidx >= (guint32)this->bounds [i].length)
358 mono_raise_exception (mono_get_exception_index_out_of_range ());
359 ind *= this->bounds [i].length;
364 ea = (gpointer*)((char*)this->vector + esize);
372 mono_array_new_va (MonoMethod *cm, ...)
374 MonoDomain *domain = mono_domain_get ();
377 guint32 *lower_bounds;
384 pcount = mono_method_signature (cm)->param_count;
385 rank = cm->klass->rank;
389 lengths = alloca (sizeof (guint32) * pcount);
390 for (i = 0; i < pcount; ++i)
391 lengths [i] = d = va_arg(ap, int);
393 if (rank == pcount) {
394 /* Only lengths provided. */
397 g_assert (pcount == (rank * 2));
398 /* lower bounds are first. */
399 lower_bounds = lengths;
404 return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
408 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
415 //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
417 mono_class_init (field->parent);
419 vtable = mono_class_vtable (domain, field->parent);
420 if (!vtable->initialized)
421 mono_runtime_class_init (vtable);
423 //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
425 if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
426 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
428 addr = (char*)vtable->data + field->offset;
434 mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context)
436 MonoClass *handle_class;
440 res = mono_ldtoken (image, token, &handle_class, context);
441 mono_class_init (handle_class);
447 mono_fconv_u8 (double v)
452 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
454 mono_fconv_i8 (double v)
456 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
462 mono_fconv_u4 (double v)
464 /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
469 /* Solaris doesn't have trunc */
471 extern long double aintl (long double);
474 /* FIXME: This means we will never throw overflow exceptions */
477 #endif /* HAVE_TRUNC */
480 mono_fconv_ovf_i8 (double v)
488 if (isnan(v) || trunc (v) != res) {
489 mono_raise_exception (mono_get_exception_overflow ());
495 mono_fconv_ovf_u8 (double v)
503 if (isnan(v) || trunc (v) != res) {
504 mono_raise_exception (mono_get_exception_overflow ());
509 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
511 mono_lconv_to_r8 (gint64 a)
517 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
519 mono_lconv_to_r4 (gint64 a)
525 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
527 mono_conv_to_r8_un (guint32 a)
533 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
535 mono_lconv_to_r8_un (guint64 a)
542 helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context)
544 MonoMethod *vmethod, *inflated;
547 vmethod = mono_object_get_virtual_method (obj, method);
548 inflated = mono_class_inflate_generic_method (vmethod, context, NULL);
549 inflated = mono_get_inflated_method (inflated);
550 addr = mono_compile_method (inflated);