X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Finterp%2Ftransform.c;h=0bdb158053412048eeb49db2387fdf86f22fbfb1;hb=3d47b20c62870f60d6944078b2a9cff7565c3205;hp=1d98608c61ca84c4c12910b02bd66d932228f271;hpb=d6141be2ef66d1aa789ebec692a85eeb69a2ca31;p=mono.git diff --git a/mono/mini/interp/transform.c b/mono/mini/interp/transform.c index 1d98608c61c..0bdb1580534 100644 --- a/mono/mini/interp/transform.c +++ b/mono/mini/interp/transform.c @@ -142,6 +142,132 @@ static int stack_type [] = { STACK_TYPE_VT }; +#if SIZEOF_VOID_P == 8 +#define MINT_NEG_P MINT_NEG_I8 +#define MINT_NOT_P MINT_NOT_I8 + +#define MINT_NEG_FP MINT_NEG_R8 + +#define MINT_ADD_P MINT_ADD_I8 +#define MINT_SUB_P MINT_SUB_I8 +#define MINT_MUL_P MINT_MUL_I8 +#define MINT_DIV_P MINT_DIV_I8 +#define MINT_DIV_UN_P MINT_DIV_UN_I8 +#define MINT_REM_P MINT_REM_I8 +#define MINT_REM_UN_P MINT_REM_UN_I8 +#define MINT_AND_P MINT_AND_I8 +#define MINT_OR_P MINT_OR_I8 +#define MINT_XOR_P MINT_XOR_I8 +#define MINT_SHL_P MINT_SHL_I8 +#define MINT_SHR_P MINT_SHR_I8 +#define MINT_SHR_UN_P MINT_SHR_UN_I8 + +#define MINT_CEQ_P MINT_CEQ_I8 +#define MINT_CNE_P MINT_CNE_I8 +#define MINT_CLT_P MINT_CLT_I8 +#define MINT_CLT_UN_P MINT_CLT_UN_I8 +#define MINT_CGT_P MINT_CGT_I8 +#define MINT_CGT_UN_P MINT_CGT_UN_I8 +#define MINT_CLE_P MINT_CLE_I8 +#define MINT_CLE_UN_P MINT_CLE_UN_I8 +#define MINT_CGE_P MINT_CGE_I8 +#define MINT_CGE_UN_P MINT_CGE_UN_I8 + +#define MINT_ADD_FP MINT_ADD_R8 +#define MINT_SUB_FP MINT_SUB_R8 +#define MINT_MUL_FP MINT_MUL_R8 +#define MINT_DIV_FP MINT_DIV_R8 +#define MINT_REM_FP MINT_REM_R8 + +#define MINT_CNE_FP MINT_CNE_R8 +#define MINT_CEQ_FP MINT_CEQ_R8 +#define MINT_CGT_FP MINT_CGT_R8 +#define MINT_CGE_FP MINT_CGE_R8 +#define MINT_CLT_FP MINT_CLT_R8 +#define MINT_CLE_FP MINT_CLE_R8 + +#else + +#define MINT_NEG_P MINT_NEG_I4 +#define MINT_NOT_P MINT_NOT_I4 + +#define MINT_NEG_FP MINT_NEG_R8 + +#define MINT_ADD_P MINT_ADD_I4 +#define MINT_SUB_P MINT_SUB_I4 +#define MINT_MUL_P MINT_MUL_I4 +#define MINT_DIV_P MINT_DIV_I4 +#define MINT_DIV_UN_P MINT_DIV_UN_I4 +#define MINT_REM_P MINT_REM_I4 +#define MINT_REM_UN_P MINT_REM_UN_I4 +#define MINT_AND_P MINT_AND_I4 +#define MINT_OR_P MINT_OR_I4 +#define MINT_XOR_P MINT_XOR_I4 +#define MINT_SHL_P MINT_SHL_I4 +#define MINT_SHR_P MINT_SHR_I4 +#define MINT_SHR_UN_P MINT_SHR_UN_I4 + +#define MINT_CEQ_P MINT_CEQ_I4 +#define MINT_CNE_P MINT_CNE_I4 +#define MINT_CLT_P MINT_CLT_I4 +#define MINT_CLT_UN_P MINT_CLT_UN_I4 +#define MINT_CGT_P MINT_CGT_I4 +#define MINT_CGT_UN_P MINT_CGT_UN_I4 +#define MINT_CLE_P MINT_CLE_I4 +#define MINT_CLE_UN_P MINT_CLE_UN_I4 +#define MINT_CGE_P MINT_CGE_I4 +#define MINT_CGE_UN_P MINT_CGE_UN_I4 + +#define MINT_ADD_FP MINT_ADD_R8 +#define MINT_SUB_FP MINT_SUB_R8 +#define MINT_MUL_FP MINT_MUL_R8 +#define MINT_DIV_FP MINT_DIV_R8 +#define MINT_REM_FP MINT_REM_R8 + +#define MINT_CNE_FP MINT_CNE_R8 +#define MINT_CEQ_FP MINT_CEQ_R8 +#define MINT_CGT_FP MINT_CGT_R8 +#define MINT_CGE_FP MINT_CGE_R8 +#define MINT_CLT_FP MINT_CLT_R8 +#define MINT_CLE_FP MINT_CLE_R8 + +#endif + +typedef struct { + const gchar *op_name; + guint16 insn [3]; +} MagicIntrinsic; + +// static const MagicIntrinsic int_binop[] = { + +static const MagicIntrinsic int_unnop[] = { + { "op_UnaryPlus", {MINT_NOP, MINT_NOP, MINT_NOP}}, + { "op_UnaryNegation", {MINT_NEG_P, MINT_NEG_P, MINT_NEG_FP}}, + { "op_OnesComplement", {MINT_NOT_P, MINT_NOT_P, MINT_NIY}} +}; + +static const MagicIntrinsic int_binop[] = { + { "op_Addition", {MINT_ADD_P, MINT_ADD_P, MINT_ADD_FP}}, + { "op_Subtraction", {MINT_SUB_P, MINT_SUB_P, MINT_SUB_FP}}, + { "op_Multiply", {MINT_MUL_P, MINT_MUL_P, MINT_MUL_FP}}, + { "op_Division", {MINT_DIV_P, MINT_DIV_UN_P, MINT_DIV_FP}}, + { "op_Modulus", {MINT_REM_P, MINT_REM_UN_P, MINT_REM_FP}}, + { "op_BitwiseAnd", {MINT_AND_P, MINT_AND_P, MINT_NIY}}, + { "op_BitwiseOr", {MINT_OR_P, MINT_OR_P, MINT_NIY}}, + { "op_ExclusiveOr", {MINT_XOR_P, MINT_XOR_P, MINT_NIY}}, + { "op_LeftShift", {MINT_SHL_P, MINT_SHL_P, MINT_NIY}}, + { "op_RightShift", {MINT_SHR_P, MINT_SHR_UN_P, MINT_NIY}}, +}; + +static const MagicIntrinsic int_cmpop[] = { + { "op_Inequality", {MINT_CNE_P, MINT_CNE_P, MINT_CNE_FP}}, + { "op_Equality", {MINT_CEQ_P, MINT_CEQ_P, MINT_CEQ_FP}}, + { "op_GreaterThan", {MINT_CGT_P, MINT_CGT_UN_P, MINT_CGT_FP}}, + { "op_GreaterThanOrEqual", {MINT_CGE_P, MINT_CGE_UN_P, MINT_CGE_FP}}, + { "op_LessThan", {MINT_CLT_P, MINT_CLT_UN_P, MINT_CLT_FP}}, + { "op_LessThanOrEqual", {MINT_CLE_P, MINT_CLE_UN_P, MINT_CLE_FP}} +}; + static void grow_code (TransformData *td) { @@ -315,8 +441,9 @@ shift_op(TransformData *td, int mint_op) } static int -mint_type(MonoType *type) +mint_type(MonoType *type_) { + MonoType *type = mini_native_type_replace_type (type_); if (type->byref) return MINT_TYPE_P; enum_type: @@ -700,6 +827,32 @@ jit_call_supported (MonoMethod *method, MonoMethodSignature *sig) return FALSE; } +static inline gboolean +type_size (MonoType *type) +{ + if (type->type == MONO_TYPE_I4 || type->type == MONO_TYPE_U4) + return 4; + else if (type->type == MONO_TYPE_I8 || type->type == MONO_TYPE_U8) + return 8; + else if (type->type == MONO_TYPE_R4 && !type->byref) + return 4; + else if (type->type == MONO_TYPE_R8 && !type->byref) + return 8; + return SIZEOF_VOID_P; +} + +static int mono_class_get_magic_index (MonoClass *k) +{ + if (mono_class_is_magic_int (k)) + return !strcmp ("nint", k->name) ? 0 : 1; + + if (mono_class_is_magic_float (k)) + return 2; + + return -1; +} + + static void interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target_method, MonoDomain *domain, MonoGenericContext *generic_context, unsigned char *is_bb_start, int body_start_offset, MonoClass *constrained_class, gboolean readonly) { @@ -761,30 +914,151 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target /* Intrinsics */ if (target_method) { + const char *tm = target_method->name; + int type_index = mono_class_get_magic_index (target_method->klass); + if (target_method->klass == mono_defaults.string_class) { - if (target_method->name [0] == 'g') { - if (strcmp (target_method->name, "get_Chars") == 0) + if (tm [0] == 'g') { + if (strcmp (tm, "get_Chars") == 0) op = MINT_GETCHR; - else if (strcmp (target_method->name, "get_Length") == 0) + else if (strcmp (tm, "get_Length") == 0) op = MINT_STRLEN; } + } else if (type_index >= 0) { + MonoClass *magic_class = target_method->klass; + + const int mt = mint_type (&magic_class->byval_arg); + if (!strcmp (".ctor", tm)) { + MonoType *arg = csignature->params [0]; + /* depending on SIZEOF_VOID_P and the type of the value passed to the .ctor we either have to CONV it, or do nothing */ + int arg_size = type_size (arg); + + if (arg_size > SIZEOF_VOID_P) { // 8 -> 4 + switch (type_index) { + case 0: case 1: + ADD_CODE (td, MINT_CONV_I8_I4); + break; + case 2: + // ADD_CODE (td, MINT_CONV_R8_R4); + break; + } + } + + if (arg_size < SIZEOF_VOID_P) { // 4 -> 8 + switch (type_index) { + case 0: case 1: + ADD_CODE (td, MINT_CONV_I4_I8); + break; + case 2: + ADD_CODE (td, MINT_CONV_R4_R8); + break; + } + } + + switch (type_index) { + case 0: case 1: +#if SIZEOF_VOID_P == 4 + ADD_CODE (td, MINT_STIND_I4); +#else + ADD_CODE (td, MINT_STIND_I8); +#endif + break; + case 2: +#if SIZEOF_VOID_P == 4 + ADD_CODE (td, MINT_STIND_R4); +#else + ADD_CODE (td, MINT_STIND_R8); +#endif + break; + } + + td->sp -= 2; + td->ip += 5; + return; + } else if (!strcmp ("op_Implicit", tm ) || !strcmp ("op_Explicit", tm)) { + int arg_size = type_size (csignature->params [0]); + if (arg_size > SIZEOF_VOID_P) { // 8 -> 4 + switch (type_index) { + case 0: case 1: + ADD_CODE (td, MINT_CONV_I8_I4); + break; + case 2: + // ADD_CODE (td, MINT_CONV_R4_R8); + break; + } + } + + if (arg_size < SIZEOF_VOID_P) { // 4 -> 8 + switch (type_index) { + case 0: case 1: + ADD_CODE (td, MINT_CONV_I4_I8); + break; + case 2: + ADD_CODE (td, MINT_CONV_R4_R8); + break; + } + } + + SET_TYPE (td->sp - 1, stack_type [mt], magic_class); + td->ip += 5; + return; + } else if (!strcmp (".cctor", tm)) { + /* white list */ + goto no_intrinsic; + } else if (!strcmp ("Parse", tm)) { + /* white list */ + goto no_intrinsic; + } + + for (i = 0; i < sizeof (int_unnop) / sizeof (MagicIntrinsic); ++i) { + if (!strcmp (int_unnop [i].op_name, tm)) { + ADD_CODE (td, int_unnop [i].insn [type_index]); + SET_TYPE (td->sp - 1, stack_type [mt], magic_class); + td->ip += 5; + return; + } + } + + for (i = 0; i < sizeof (int_binop) / sizeof (MagicIntrinsic); ++i) { + if (!strcmp (int_binop [i].op_name, tm)) { + ADD_CODE (td, int_binop [i].insn [type_index]); + td->sp -= 1; + SET_TYPE (td->sp - 1, stack_type [mt], magic_class); + td->ip += 5; + return; + } + } + + for (i = 0; i < sizeof (int_cmpop) / sizeof (MagicIntrinsic); ++i) { + if (!strcmp (int_cmpop [i].op_name, tm)) { + MonoClass *k = mono_defaults.boolean_class; + ADD_CODE (td, int_cmpop [i].insn [type_index]); + td->sp -= 1; + SET_TYPE (td->sp - 1, stack_type [mint_type (&k->byval_arg)], k); + td->ip += 5; + return; + } + } + + g_error ("TODO: %s", tm); } else if (mono_class_is_subclass_of (target_method->klass, mono_defaults.array_class, FALSE)) { - if (!strcmp (target_method->name, "get_Rank")) { + if (!strcmp (tm, "get_Rank")) { op = MINT_ARRAY_RANK; - } else if (!strcmp (target_method->name, "get_Length")) { + } else if (!strcmp (tm, "get_Length")) { op = MINT_LDLEN; - } else if (!strcmp (target_method->name, "Address")) { + } else if (!strcmp (tm, "Address")) { op = readonly ? MINT_LDELEMA : MINT_LDELEMA_TC; } } else if (target_method->klass->image == mono_defaults.corlib && (strcmp (target_method->klass->name_space, "System.Diagnostics") == 0) && (strcmp (target_method->klass->name, "Debugger") == 0)) { - if (!strcmp (target_method->name, "Break") && csignature->param_count == 0) { + if (!strcmp (tm, "Break") && csignature->param_count == 0) { if (mini_should_insert_breakpoint (method)) op = MINT_BREAK; } } } +no_intrinsic: if (constrained_class) { if (constrained_class->enumtype && !strcmp (target_method->name, "GetHashCode")) { @@ -881,7 +1155,11 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target return; } else { /* mheader might not exist if this is a delegate invoc, etc */ - if (mheader && *mheader->code == CEE_RET && called_inited) { + gboolean has_vt_arg = FALSE; + for (i = 0; i < csignature->param_count; i++) + has_vt_arg |= !mini_type_is_reference (csignature->params [i]); + + if (mheader && *mheader->code == CEE_RET && called_inited && !has_vt_arg) { if (td->verbose_level) g_print ("Inline (empty) call of %s.%s\n", target_method->klass->name, target_method->name); for (i = 0; i < csignature->param_count; i++) { @@ -1302,7 +1580,7 @@ save_seq_points (TransformData *td) } info = mono_seq_point_info_new (array->len, TRUE, array->data, TRUE, &seq_info_size); - mono_jit_stats.allocated_seq_points_size += seq_info_size; + InterlockedAdd (&mono_jit_stats.allocated_seq_points_size, seq_info_size); g_byte_array_free (array, TRUE); @@ -1514,6 +1792,9 @@ generate (MonoMethod *method, InterpMethod *rtm, unsigned char *is_bb_start, Mon } } + if (rtm->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER) + ADD_CODE (td, MINT_PROF_ENTER); + if (sym_seq_points) { InterpBasicBlock *cbb = td->offset_to_bb [0]; g_assert (cbb); @@ -2222,6 +2503,7 @@ generate (MonoMethod *method, InterpMethod *rtm, unsigned char *is_bb_start, Mon #endif break; case STACK_TYPE_MP: + case STACK_TYPE_O: break; default: g_assert_not_reached (); @@ -2454,31 +2736,38 @@ generate (MonoMethod *method, InterpMethod *rtm, unsigned char *is_bb_start, Mon csignature = mono_method_signature (m); klass = m->klass; + td->sp -= csignature->param_count; - ADD_CODE(td, MINT_NEWOBJ); - ADD_CODE(td, get_data_item_index (td, mono_interp_get_imethod (domain, m, &error))); - mono_error_cleanup (&error); /* FIXME: don't swallow the error */ + if (mono_class_is_magic_int (klass) || mono_class_is_magic_float (klass)) { + ADD_CODE (td, MINT_NEWOBJ_MAGIC); + ADD_CODE (td, get_data_item_index (td, mono_interp_get_imethod (domain, m, &error))); + PUSH_TYPE (td, stack_type [mint_type (&klass->byval_arg)], klass); + } else { + ADD_CODE(td, MINT_NEWOBJ); + ADD_CODE(td, get_data_item_index (td, mono_interp_get_imethod (domain, m, &error))); + mono_error_cleanup (&error); /* FIXME: don't swallow the error */ - if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) { - vt_res_size = mono_class_value_size (klass, NULL); - PUSH_VT (td, vt_res_size); - } - for (i = 0; i < csignature->param_count; ++i) { - int mt = mint_type(csignature->params [i]); - if (mt == MINT_TYPE_VT) { - MonoClass *k = mono_class_from_mono_type (csignature->params [i]); - gint32 size = mono_class_value_size (k, NULL); - size = (size + 7) & ~7; - vt_stack_used += size; + if (mint_type (&klass->byval_arg) == MINT_TYPE_VT) { + vt_res_size = mono_class_value_size (klass, NULL); + PUSH_VT (td, vt_res_size); } + for (i = 0; i < csignature->param_count; ++i) { + int mt = mint_type(csignature->params [i]); + if (mt == MINT_TYPE_VT) { + MonoClass *k = mono_class_from_mono_type (csignature->params [i]); + gint32 size = mono_class_value_size (k, NULL); + size = (size + 7) & ~7; + vt_stack_used += size; + } + } + if (vt_stack_used != 0 || vt_res_size != 0) { + ADD_CODE(td, MINT_VTRESULT); + ADD_CODE(td, vt_res_size); + WRITE32(td, &vt_stack_used); + td->vt_sp -= vt_stack_used; + } + PUSH_TYPE (td, stack_type [mint_type (&klass->byval_arg)], klass); } - if (vt_stack_used != 0 || vt_res_size != 0) { - ADD_CODE(td, MINT_VTRESULT); - ADD_CODE(td, vt_res_size); - WRITE32(td, &vt_stack_used); - td->vt_sp -= vt_stack_used; - } - PUSH_TYPE (td, stack_type [mint_type (&klass->byval_arg)], klass); break; } case CEE_CASTCLASS: @@ -3750,6 +4039,7 @@ generate (MonoMethod *method, InterpMethod *rtm, unsigned char *is_bb_start, Mon case CEE_TAIL_: ++td->ip; /* FIX: should do something? */; + // TODO: This should raise a method_tail_call profiler event. break; case CEE_INITOBJ: CHECK_STACK(td, 1); @@ -3973,6 +4263,7 @@ mono_interp_transform_init (void) MonoException * mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context) { + MonoError error; int i, align, size, offset; MonoMethod *method = imethod->method; MonoImage *image = method->klass->image; @@ -3990,9 +4281,11 @@ mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context) MonoDomain *domain = imethod->domain; // g_printerr ("TRANSFORM(0x%016lx): begin %s::%s\n", mono_thread_current (), method->klass->name, method->name); - method_class_vt = mono_class_vtable (domain, imethod->method->klass); + method_class_vt = mono_class_vtable_full (domain, imethod->method->klass, &error); + if (!is_ok (&error)) + return mono_error_convert_to_exception (&error); + if (!method_class_vt->initialized) { - MonoError error; jmp_buf env; InterpFrame *last_env_frame = context->env_frame; jmp_buf *old_env = context->current_env; @@ -4130,12 +4423,10 @@ mono_interp_transform_method (InterpMethod *imethod, ThreadContext *context) break; case MonoInlineMethod: if (method->wrapper_type == MONO_WRAPPER_NONE && *ip != CEE_CALLI) { - m = mono_get_method_full (image, read32 (ip + 1), NULL, generic_context); - if (m == NULL) { + m = mono_get_method_checked (image, read32 (ip + 1), NULL, generic_context, &error); + if (!is_ok (&error)) { g_free (is_bb_start); - g_error ("FIXME: where to get method and class string?"); - return NULL; - // return mono_get_exception_missing_method (); + return mono_error_convert_to_exception (&error); } mono_class_init (m->klass); if (!mono_class_is_interface (m->klass))