X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fjit-icalls.c;h=fd1de882efff4dae1fadada00b49555dc741d9f9;hb=0717f141b92db56481cc09af70c026d7ffad8921;hp=03ed1328978b0d9b949ec60c4519834917c7319b;hpb=9869ae24b88761ab261c4311e24f7383b4af3f02;p=mono.git diff --git a/mono/mini/jit-icalls.c b/mono/mini/jit-icalls.c index 03ed1328978..fd1de882eff 100644 --- a/mono/mini/jit-icalls.c +++ b/mono/mini/jit-icalls.c @@ -7,8 +7,12 @@ * * (C) 2002 Ximian, Inc. */ - +#include #include +#include +#ifdef HAVE_ALLOCA_H +#include +#endif #include "jit-icalls.h" @@ -19,38 +23,50 @@ mono_ldftn (MonoMethod *method) MONO_ARCH_SAVE_REGS; - addr = mono_create_jump_trampoline (mono_domain_get (), method, TRUE); + addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE); return mono_create_ftnptr (mono_domain_get (), addr); } -/* - * Same as mono_ldftn, but do not add a synchronized wrapper. Used in the - * synchronized wrappers to avoid infinite recursion. - */ -void* -mono_ldftn_nosync (MonoMethod *method) +static void* +ldvirtfn_internal (MonoObject *obj, MonoMethod *method, gboolean gshared) { - gpointer addr; + MonoMethod *res; MONO_ARCH_SAVE_REGS; - addr = mono_create_jump_trampoline (mono_domain_get (), method, FALSE); + if (obj == NULL) + mono_raise_exception (mono_get_exception_null_reference ()); - return mono_create_ftnptr (mono_domain_get (), addr); + res = mono_object_get_virtual_method (obj, method); + + if (gshared && method->is_inflated && mono_method_get_context (method)->method_inst) { + MonoGenericContext context = { NULL, NULL }; + + if (res->klass->generic_class) + context.class_inst = res->klass->generic_class->context.class_inst; + else if (res->klass->generic_container) + context.class_inst = res->klass->generic_container->context.class_inst; + context.method_inst = mono_method_get_context (method)->method_inst; + + res = mono_class_inflate_generic_method (res, &context); + } + + /* An rgctx wrapper is added by the trampolines no need to do it here */ + + return mono_ldftn (res); } void* mono_ldvirtfn (MonoObject *obj, MonoMethod *method) { - MONO_ARCH_SAVE_REGS; - - if (obj == NULL) - mono_raise_exception (mono_get_exception_null_reference ()); - - method = mono_object_get_virtual_method (obj, method); + return ldvirtfn_internal (obj, method, FALSE); +} - return mono_ldftn (method); +void* +mono_ldvirtfn_gshared (MonoObject *obj, MonoMethod *method) +{ + return ldvirtfn_internal (obj, method, TRUE); } void @@ -271,7 +287,7 @@ mono_irem_un (guint32 a, guint32 b) #endif -#ifdef MONO_ARCH_EMULATE_MUL_DIV +#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF) gint32 mono_imul (gint32 a, gint32 b) @@ -290,7 +306,7 @@ mono_imul_ovf (gint32 a, gint32 b) res = (gint64)a * (gint64)b; - if ((res > 0x7fffffffL) || (res < -2147483648)) + if ((res > 0x7fffffffL) || (res < -2147483648LL)) mono_raise_exception (mono_get_exception_overflow ()); return res; @@ -310,7 +326,9 @@ mono_imul_ovf_un (guint32 a, guint32 b) return res; } +#endif +#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT) double mono_fdiv (double a, double b) { @@ -417,58 +435,210 @@ mono_lshr (gint64 a, gint32 shamt) #endif -/** - * ves_array_element_address: - * @this: a pointer to the array object - * - * Returns: the address of an array element. - */ -gpointer -ves_array_element_address (MonoArray *this, ...) +#ifdef MONO_ARCH_SOFT_FLOAT + +double +mono_fsub (double a, double b) { - MonoClass *class; - va_list ap; - int i, ind, esize, realidx; - gpointer ea; + return a - b; +} - MONO_ARCH_SAVE_REGS; +double +mono_fadd (double a, double b) +{ + return a + b; +} - g_assert (this != NULL); +double +mono_fmul (double a, double b) +{ + return a * b; +} - va_start(ap, this); +double +mono_fneg (double a) +{ + return -a; +} - class = this->obj.vtable->klass; +double +mono_fconv_r4 (double a) +{ + return (float)a; +} - g_assert (this->bounds != NULL); +double +mono_conv_to_r8 (int a) +{ + return (double)a; +} - esize = mono_array_element_size (class); - ind = va_arg(ap, int); - ind -= (int)this->bounds [0].lower_bound; - if ((guint32)ind >= (guint32)this->bounds [0].length) - mono_raise_exception (mono_get_exception_index_out_of_range ()); - for (i = 1; i < class->rank; i++) { - realidx = va_arg(ap, int) - (int)this->bounds [i].lower_bound; - if ((guint32)realidx >= (guint32)this->bounds [i].length) - mono_raise_exception (mono_get_exception_index_out_of_range ()); - ind *= this->bounds [i].length; - ind += realidx; - } - esize *= ind; +double +mono_conv_to_r4 (int a) +{ + return (double)(float)a; +} - ea = (gpointer*)(gpointer)((char*)this->vector + esize); +gint8 +mono_fconv_i1 (double a) +{ + return (gint8)a; +} - va_end(ap); +gint16 +mono_fconv_i2 (double a) +{ + return (gint16)a; +} + +gint32 +mono_fconv_i4 (double a) +{ + return (gint32)a; +} + +guint8 +mono_fconv_u1 (double a) +{ + return (guint8)a; +} + +guint16 +mono_fconv_u2 (double a) +{ + return (guint16)a; +} + +gboolean +mono_fcmp_eq (double a, double b) +{ + return a == b; +} + +gboolean +mono_fcmp_ge (double a, double b) +{ + return a >= b; +} + +gboolean +mono_fcmp_gt (double a, double b) +{ + return a > b; +} + +gboolean +mono_fcmp_le (double a, double b) +{ + return a <= b; +} + +gboolean +mono_fcmp_lt (double a, double b) +{ + return a < b; +} + +gboolean +mono_fcmp_ne_un (double a, double b) +{ + return isunordered (a, b) || a != b; +} + +gboolean +mono_fcmp_ge_un (double a, double b) +{ + return isunordered (a, b) || a >= b; +} + +gboolean +mono_fcmp_gt_un (double a, double b) +{ + return isunordered (a, b) || a > b; +} + +gboolean +mono_fcmp_le_un (double a, double b) +{ + return isunordered (a, b) || a <= b; +} + +gboolean +mono_fcmp_lt_un (double a, double b) +{ + return isunordered (a, b) || a < b; +} + +gboolean +mono_fceq (double a, double b) +{ + return a == b; +} + +gboolean +mono_fcgt (double a, double b) +{ + return a > b; +} + +gboolean +mono_fcgt_un (double a, double b) +{ + return isunordered (a, b) || a > b; +} + +gboolean +mono_fclt (double a, double b) +{ + return a < b; +} + +gboolean +mono_fclt_un (double a, double b) +{ + return isunordered (a, b) || a < b; +} + +gboolean +mono_isfinite (double a) +{ +#ifdef HAVE_ISFINITE + return isfinite (a); +#else + g_assert_not_reached (); + return TRUE; +#endif +} + +double +mono_fload_r4 (float *ptr) +{ + return *ptr; +} - return ea; +void +mono_fstore_r4 (double val, float *ptr) +{ + *ptr = (float)val; } +/* returns the integer bitpattern that is passed in the regs or stack */ +guint32 +mono_fload_r4_arg (double val) +{ + float v = (float)val; + return *(guint32*)&v; +} + +#endif + MonoArray * mono_array_new_va (MonoMethod *cm, ...) { MonoDomain *domain = mono_domain_get (); va_list ap; - guint32 *lengths; - guint32 *lower_bounds; + uintptr_t *lengths; + intptr_t *lower_bounds; int pcount; int rank; int i, d; @@ -480,22 +650,22 @@ mono_array_new_va (MonoMethod *cm, ...) va_start (ap, cm); - lengths = alloca (sizeof (guint32) * pcount); + lengths = alloca (sizeof (uintptr_t) * pcount); for (i = 0; i < pcount; ++i) lengths [i] = d = va_arg(ap, int); if (rank == pcount) { /* Only lengths provided. */ if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) { - lower_bounds = alloca (sizeof (guint32) * rank); - memset (lower_bounds, 0, sizeof (guint32) * rank); + lower_bounds = alloca (sizeof (intptr_t) * rank); + memset (lower_bounds, 0, sizeof (intptr_t) * rank); } else { lower_bounds = NULL; } } else { g_assert (pcount == (rank * 2)); /* lower bounds are first. */ - lower_bounds = lengths; + lower_bounds = (intptr_t*)lengths; lengths += rank; } va_end(ap); @@ -503,6 +673,94 @@ mono_array_new_va (MonoMethod *cm, ...) return mono_array_new_full (domain, cm->klass, lengths, lower_bounds); } +/* Specialized version of mono_array_new_va () which avoids varargs */ +MonoArray * +mono_array_new_1 (MonoMethod *cm, guint32 length) +{ + MonoDomain *domain = mono_domain_get (); + uintptr_t lengths [1]; + intptr_t *lower_bounds; + int pcount; + int rank; + + MONO_ARCH_SAVE_REGS; + + pcount = mono_method_signature (cm)->param_count; + rank = cm->klass->rank; + + lengths [0] = length; + + g_assert (rank == pcount); + + if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) { + lower_bounds = alloca (sizeof (intptr_t) * rank); + memset (lower_bounds, 0, sizeof (intptr_t) * rank); + } else { + lower_bounds = NULL; + } + + return mono_array_new_full (domain, cm->klass, lengths, lower_bounds); +} + +MonoArray * +mono_array_new_2 (MonoMethod *cm, guint32 length1, guint32 length2) +{ + MonoDomain *domain = mono_domain_get (); + uintptr_t lengths [2]; + intptr_t *lower_bounds; + int pcount; + int rank; + + MONO_ARCH_SAVE_REGS; + + pcount = mono_method_signature (cm)->param_count; + rank = cm->klass->rank; + + lengths [0] = length1; + lengths [1] = length2; + + g_assert (rank == pcount); + + if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) { + lower_bounds = alloca (sizeof (intptr_t) * rank); + memset (lower_bounds, 0, sizeof (intptr_t) * rank); + } else { + lower_bounds = NULL; + } + + return mono_array_new_full (domain, cm->klass, lengths, lower_bounds); +} + +MonoArray * +mono_array_new_3 (MonoMethod *cm, guint32 length1, guint32 length2, guint32 length3) +{ + MonoDomain *domain = mono_domain_get (); + uintptr_t lengths [3]; + intptr_t *lower_bounds; + int pcount; + int rank; + + MONO_ARCH_SAVE_REGS; + + pcount = mono_method_signature (cm)->param_count; + rank = cm->klass->rank; + + lengths [0] = length1; + lengths [1] = length2; + lengths [2] = length3; + + g_assert (rank == pcount); + + if (cm->klass->byval_arg.type == MONO_TYPE_ARRAY) { + lower_bounds = alloca (sizeof (intptr_t) * rank); + memset (lower_bounds, 0, sizeof (intptr_t) * rank); + } else { + lower_bounds = NULL; + } + + return mono_array_new_full (domain, cm->klass, lengths, lower_bounds); +} + gpointer mono_class_static_field_address (MonoDomain *domain, MonoClassField *field) { @@ -515,7 +773,7 @@ mono_class_static_field_address (MonoDomain *domain, MonoClassField *field) mono_class_init (field->parent); - vtable = mono_class_vtable (domain, field->parent); + vtable = mono_class_vtable_full (domain, field->parent, TRUE); if (!vtable->initialized) mono_runtime_class_init (vtable); @@ -542,6 +800,23 @@ mono_ldtoken_wrapper (MonoImage *image, int token, MonoGenericContext *context) return res; } +gpointer +mono_ldtoken_wrapper_generic_shared (MonoImage *image, int token, MonoMethod *method) +{ + MonoMethodSignature *sig = mono_method_signature (method); + MonoGenericContext *generic_context; + + if (sig->is_inflated) { + generic_context = mono_method_get_context (method); + } else { + MonoGenericContainer *generic_container = mono_method_get_generic_container (method); + g_assert (generic_container); + generic_context = &generic_container->context; + } + + return mono_ldtoken_wrapper (image, token, generic_context); +} + guint64 mono_fconv_u8 (double v) { @@ -596,12 +871,26 @@ mono_fconv_ovf_u8 (double v) guint64 res; MONO_ARCH_SAVE_REGS; - +/* + * The soft-float implementation of some ARM devices have a buggy guin64 to double + * conversion that it looses precision even when the integer if fully representable + * as a double. + * + * This was found with 4294967295ull, converting to double and back looses one bit of precision. + * + * To work around this issue we test for value boundaries instead. + */ +#if defined(__arm__) && MONO_ARCH_SOFT_FLOAT + if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) { + mono_raise_exception (mono_get_exception_overflow ()); + } + res = (guint64)v; +#else res = (guint64)v; - if (isnan(v) || trunc (v) != res) { mono_raise_exception (mono_get_exception_overflow ()); } +#endif return res; } @@ -638,27 +927,25 @@ mono_lconv_to_r8_un (guint64 a) #endif gpointer -mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, MonoGenericContext *context, gpointer *this_arg) +mono_helper_compile_generic_method (MonoObject *obj, MonoMethod *method, gpointer *this_arg) { - MonoMethod *vmethod, *inflated; + MonoMethod *vmethod; gpointer addr; + MonoGenericContext *context = mono_method_get_context (method); + + mono_jit_stats.generic_virtual_invocations++; if (obj == NULL) mono_raise_exception (mono_get_exception_null_reference ()); vmethod = mono_object_get_virtual_method (obj, method); + g_assert (!vmethod->klass->generic_container); + g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->context.class_inst->is_open); + g_assert (!context->method_inst || !context->method_inst->is_open); - /* 'vmethod' is partially inflated. All the blanks corresponding to the type parameters of the - declaring class have been inflated. We still need to fully inflate the method parameters. + addr = mono_compile_method (vmethod); - FIXME: This code depends on the declaring class being fully inflated, since we inflate it twice with - the same context. - */ - g_assert (!vmethod->klass->generic_container); - g_assert (!vmethod->klass->generic_class || !vmethod->klass->generic_class->inst->is_open); - g_assert (!context->gmethod || !context->gmethod->inst->is_open); - inflated = mono_class_inflate_generic_method (vmethod, context); - inflated = mono_get_inflated_method (inflated); - addr = mono_compile_method (inflated); + if (mono_method_needs_static_rgctx_invoke (vmethod, FALSE)) + addr = mono_create_static_rgctx_trampoline (vmethod, addr); /* Since this is a virtual call, have to unbox vtypes */ if (obj->vtable->klass->valuetype) @@ -690,3 +977,61 @@ mono_helper_newobj_mscorlib (guint32 idx) return mono_object_new (mono_domain_get (), klass); } + +/* + * On some architectures, gdb doesn't like encountering the cpu breakpoint instructions + * in generated code. So instead we emit a call to this function and place a gdb + * breakpoint here. + */ +void +mono_break (void) +{ +} + +MonoException * +mono_create_corlib_exception_0 (guint32 token) +{ + return mono_exception_from_token (mono_defaults.corlib, token); +} + +MonoException * +mono_create_corlib_exception_1 (guint32 token, MonoString *arg) +{ + return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg, NULL); +} + +MonoException * +mono_create_corlib_exception_2 (guint32 token, MonoString *arg1, MonoString *arg2) +{ + return mono_exception_from_token_two_strings (mono_defaults.corlib, token, arg1, arg2); +} + +MonoObject* +mono_object_castclass (MonoObject *obj, MonoClass *klass) +{ + if (!obj) + return NULL; + + if (mono_object_isinst (obj, klass)) + return obj; + + mono_raise_exception (mono_exception_from_name (mono_defaults.corlib, + "System", "InvalidCastException")); + + return NULL; +} + +gpointer +mono_get_native_calli_wrapper (MonoImage *image, MonoMethodSignature *sig, gpointer func) +{ + MonoMarshalSpec **mspecs; + MonoMethodPInvoke piinfo; + MonoMethod *m; + + mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1); + memset (&piinfo, 0, sizeof (piinfo)); + + m = mono_marshal_get_native_func_wrapper (image, sig, &piinfo, mspecs, func); + + return mono_compile_method (m); +}