X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini.c;h=01576ad569872f7facbd768c0d41c8a9fc608479;hb=663b53f63dee6f5cd7a9780edec216f68ed81afe;hp=6c6bbdc26fbbf1034391d43d4d2abf403c457b21;hpb=f4774442eaf92333012ae8b0a431739b4efe22bf;p=mono.git diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 6c6bbdc26fb..01576ad5698 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -367,6 +367,8 @@ mono_print_method_from_ip (void *ip) MonoDomain *domain = mono_domain_get (); MonoDomain *target_domain = mono_domain_get (); FindTrampUserData user_data; + MonoGenericSharingContext*gsctx; + const char *shared_type; ji = mini_jit_info_table_find (domain, ip, &target_domain); if (!ji) { @@ -388,7 +390,16 @@ mono_print_method_from_ip (void *ip) method = mono_method_full_name (ji->method, TRUE); source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), target_domain); - g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name); + gsctx = mono_jit_info_get_generic_sharing_context (ji); + shared_type = ""; + if (gsctx) { + if (gsctx->var_is_vt || gsctx->mvar_is_vt) + shared_type = "gsharedvt "; + else + shared_type = "gshared "; + } + + g_print ("IP %p at offset 0x%x of %smethod %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), shared_type, method, ji->code_start, (char*)ji->code_start + ji->code_size, target_domain, target_domain->friendly_name); if (source) g_print ("%s:%d\n", source->source_file, source->row); @@ -601,6 +612,35 @@ mono_tramp_info_free (MonoTrampInfo *info) g_free (info); } +G_GNUC_UNUSED static void +break_count (void) +{ +} + +/* + * Runtime debugging tool, use if (debug_count ()) else to do the first COUNT times, then do afterwards. + * Set a breakpoint in break_count () to break the last time is done. + */ +G_GNUC_UNUSED gboolean +mono_debug_count (void) +{ + static int count = 0; + count ++; + + if (!getenv ("COUNT")) + return TRUE; + + if (count == atoi (getenv ("COUNT"))) { + break_count (); + } + + if (count > atoi (getenv ("COUNT"))) { + return FALSE; + } + + return TRUE; +} + #define MONO_INIT_VARINFO(vi,id) do { \ (vi)->range.first_use.pos.bid = 0xffff; \ (vi)->reg = -1; \ @@ -833,12 +873,10 @@ handle_enum: goto handle_enum; case MONO_TYPE_VAR: case MONO_TYPE_MVAR: - /* FIXME: all the arguments must be references for now, - * later look inside cfg and see if the arg num is - * really a reference - */ - g_assert (cfg->generic_sharing_context); - return OP_STORE_MEMBASE_REG; + if (mini_type_var_is_vt (cfg, type)) + return OP_STOREV_MEMBASE; + else + return OP_STORE_MEMBASE_REG; default: g_error ("unknown type 0x%02x in type_to_store_membase", type->type); } @@ -899,12 +937,11 @@ mono_type_to_load_membase (MonoCompile *cfg, MonoType *type) break; case MONO_TYPE_VAR: case MONO_TYPE_MVAR: - /* FIXME: all the arguments must be references for now, - * later look inside cfg and see if the arg num is - * really a reference - */ g_assert (cfg->generic_sharing_context); - return OP_LOAD_MEMBASE; + if (mini_type_var_is_vt (cfg, type)) + return OP_LOADV_MEMBASE; + else + return OP_LOAD_MEMBASE; default: g_error ("unknown type 0x%02x in type_to_load_membase", type->type); } @@ -915,12 +952,12 @@ static guint mini_type_to_ldind (MonoCompile* cfg, MonoType *type) { if (cfg->generic_sharing_context && !type->byref) { - /* FIXME: all the arguments must be references for now, - * later look inside cfg and see if the arg num is - * really a reference - */ - if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) - return CEE_LDIND_REF; + if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) { + if (mini_type_var_is_vt (cfg, type)) + return CEE_LDOBJ; + else + return CEE_LDIND_REF; + } } return mono_type_to_ldind (type); } @@ -929,12 +966,12 @@ guint mini_type_to_stind (MonoCompile* cfg, MonoType *type) { if (cfg->generic_sharing_context && !type->byref) { - /* FIXME: all the arguments must be references for now, - * later look inside cfg and see if the arg num is - * really a reference - */ - if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) - return CEE_STIND_REF; + if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) { + if (mini_type_var_is_vt (cfg, type)) + return CEE_STOBJ; + else + return CEE_STIND_REF; + } } return mono_type_to_stind (type); } @@ -1124,6 +1161,9 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, inst->backend.is_pinvoke = 0; inst->dreg = vreg; + if (inst->klass->exception_type) + mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); + if (cfg->compute_gc_maps) { if (type->byref) { mono_mark_vreg_as_mp (cfg, vreg); @@ -1717,18 +1757,22 @@ mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_ vmv = current; inst = cfg->varinfo [vmv->idx]; + t = mono_type_get_underlying_type (inst->inst_vtype); + if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t)) + t = mini_get_gsharedvt_alloc_type_for_type (cfg, t); + /* inst->backend.is_pinvoke indicates native sized value types, this is used by the * pinvoke wrappers when they call functions returning structures */ - if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) { - size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align); + if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (t) && t->type != MONO_TYPE_TYPEDBYREF) { + size = mono_class_native_size (mono_class_from_mono_type (t), &align); } else { int ialign; - size = mono_type_size (inst->inst_vtype, &ialign); + size = mono_type_size (t, &ialign); align = ialign; - if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (inst->inst_vtype))) + if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (t))) align = 16; } @@ -1736,7 +1780,6 @@ mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_ if (cfg->disable_reuse_stack_slots) reuse_slot = FALSE; - t = mono_type_get_underlying_type (inst->inst_vtype); switch (t->type) { case MONO_TYPE_GENERICINST: if (!mono_type_generic_inst_is_valuetype (t)) { @@ -2010,17 +2053,24 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s vmv = l->data; inst = cfg->varinfo [vmv->idx]; + t = mono_type_get_underlying_type (inst->inst_vtype); + if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t)) + t = mini_get_gsharedvt_alloc_type_for_type (cfg, t); + /* inst->backend.is_pinvoke indicates native sized value types, this is used by the * pinvoke wrappers when they call functions returning structures */ - if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) { - size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align); + if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (t) && t->type != MONO_TYPE_TYPEDBYREF) { + size = mono_class_native_size (mono_class_from_mono_type (t), &align); } else { int ialign; - size = mono_type_size (inst->inst_vtype, &ialign); + size = mono_type_size (t, &ialign); align = ialign; - if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (inst->inst_vtype))) + if (mono_class_from_mono_type (t)->exception_type) + mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); + + if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (t))) align = 16; } @@ -2028,7 +2078,6 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s if (cfg->disable_reuse_stack_slots) reuse_slot = FALSE; - t = mono_type_get_underlying_type (inst->inst_vtype); if (t->byref) { slot_info = &scalar_stack_slots [MONO_TYPE_I]; } else { @@ -2081,9 +2130,13 @@ mono_allocate_stack_slots (MonoCompile *cfg, gboolean backward, guint32 *stack_s if (cfg->disable_reuse_ref_stack_slots) reuse_slot = FALSE; break; - + case MONO_TYPE_VAR: + case MONO_TYPE_MVAR: + slot_info = &scalar_stack_slots [t->type]; + break; default: slot_info = &scalar_stack_slots [t->type]; + break; } } @@ -2637,16 +2690,7 @@ mono_thread_abort (MonoObject *obj) (obj->vtable->klass == mono_defaults.threadabortexception_class)) { mono_thread_exit (); } else { - MonoObject *other = NULL; - MonoString *str = mono_object_to_string (obj, &other); - if (str) { - char *msg = mono_string_to_utf8 (str); - fprintf (stderr, "[ERROR] FATAL UNHANDLED EXCEPTION: %s\n", msg); - fflush (stderr); - g_free (msg); - } - - exit (mono_environment_exitcode_get ()); + mono_invoke_unhandled_exception_hook (obj); } } @@ -2878,6 +2922,10 @@ mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info) memcpy (res->data.rgctx_entry, patch_info->data.rgctx_entry, sizeof (MonoJumpInfoRgctxEntry)); res->data.rgctx_entry->data = mono_patch_info_dup_mp (mp, res->data.rgctx_entry->data); break; + case MONO_PATCH_INFO_GSHAREDVT_CALL: + res->data.gsharedvt = mono_mempool_alloc (mp, sizeof (MonoJumpInfoGSharedVtCall)); + memcpy (res->data.gsharedvt, patch_info->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall)); + break; default: break; } @@ -2914,6 +2962,8 @@ mono_patch_info_hash (gconstpointer data) case MONO_PATCH_INFO_SFLDA: case MONO_PATCH_INFO_SEQ_POINT_INFO: return (ji->type << 8) | (gssize)ji->data.target; + case MONO_PATCH_INFO_GSHAREDVT_CALL: + return (ji->type << 8) | (gssize)ji->data.gsharedvt->method; default: return (ji->type << 8); } @@ -3221,15 +3271,25 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, switch (entry->data->type) { case MONO_PATCH_INFO_CLASS: - slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method)); + slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, &entry->data->data.klass->byval_arg, entry->info_type, mono_method_get_context (entry->method)); break; case MONO_PATCH_INFO_METHOD: case MONO_PATCH_INFO_METHODCONST: - slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method)); + slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.method, entry->info_type, mono_method_get_context (entry->method)); break; case MONO_PATCH_INFO_FIELD: - slot = mono_method_lookup_or_register_other_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method)); + slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.field, entry->info_type, mono_method_get_context (entry->method)); + break; + case MONO_PATCH_INFO_SIGNATURE: + slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, entry->data->data.sig, entry->info_type, mono_method_get_context (entry->method)); break; + case MONO_PATCH_INFO_GSHAREDVT_CALL: { + MonoJumpInfoGSharedVtCall *call_info = mono_domain_alloc0 (domain, sizeof (MonoJumpInfoGSharedVtCall)); + + memcpy (call_info, entry->data->data.gsharedvt, sizeof (MonoJumpInfoGSharedVtCall)); + slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, call_info, entry->info_type, mono_method_get_context (entry->method)); + break; + } default: g_assert_not_reached (); break; @@ -3875,6 +3935,34 @@ mono_handle_out_of_line_bblock (MonoCompile *cfg) } } +#endif /* #ifndef DISABLE_JIT */ + +static MonoJitInfo* +create_jit_info_for_trampoline (MonoMethod *wrapper, MonoTrampInfo *info) +{ + MonoDomain *domain = mono_get_root_domain (); + MonoJitInfo *jinfo; + guint8 *uw_info; + guint32 info_len; + + if (info->uw_info) { + uw_info = info->uw_info; + info_len = info->uw_info_len; + } else { + uw_info = mono_unwind_ops_encode (info->unwind_ops, &info_len); + } + + jinfo = mono_domain_alloc0 (domain, MONO_SIZEOF_JIT_INFO); + jinfo->method = wrapper; + jinfo->code_start = info->code; + jinfo->code_size = info->code_size; + jinfo->used_regs = mono_cache_unwind_info (uw_info, info_len); + + return jinfo; +} + +#ifndef DISABLE_JIT + static MonoJitInfo* create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) { @@ -3883,7 +3971,7 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) MonoJitInfo *jinfo; int num_clauses; int generic_info_size, arch_eh_info_size = 0; - int holes_size = 0, num_holes = 0; + int holes_size = 0, num_holes = 0, cas_size = 0; guint32 stack_size = 0; g_assert (method_to_compile == cfg->method); @@ -3903,7 +3991,7 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) * mono_arch_get_argument_info () is not signal safe. */ arg_info = g_newa (MonoJitArgumentInfo, sig->param_count + 1); - stack_size = mono_arch_get_argument_info (sig, sig->param_count, arg_info); + stack_size = mono_arch_get_argument_info (cfg->generic_sharing_context, sig, sig->param_count, arg_info); if (stack_size) arch_eh_info_size = sizeof (MonoArchEHJitInfo); @@ -3927,6 +4015,10 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) printf ("Number of try block holes %d\n", num_holes); } + if (mono_method_has_declsec (cfg->method_to_register)) { + cas_size = sizeof (MonoMethodCasInfo); + } + if (COMPILE_LLVM (cfg)) num_clauses = cfg->llvm_ex_info_len; else @@ -3934,11 +4026,11 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) if (cfg->method->dynamic) { jinfo = g_malloc0 (MONO_SIZEOF_JIT_INFO + (num_clauses * sizeof (MonoJitExceptionInfo)) + - generic_info_size + holes_size + arch_eh_info_size); + generic_info_size + holes_size + arch_eh_info_size + cas_size); } else { jinfo = mono_domain_alloc0 (cfg->domain, MONO_SIZEOF_JIT_INFO + (num_clauses * sizeof (MonoJitExceptionInfo)) + - generic_info_size + holes_size + arch_eh_info_size); + generic_info_size + holes_size + arch_eh_info_size + cas_size); } jinfo->method = cfg->method_to_register; @@ -3946,8 +4038,8 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) jinfo->code_size = cfg->code_len; jinfo->used_regs = cfg->used_int_regs; jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0; - jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */ jinfo->num_clauses = num_clauses; + if (COMPILE_LLVM (cfg)) jinfo->from_llvm = TRUE; @@ -3961,7 +4053,11 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) gi = mono_jit_info_get_generic_jit_info (jinfo); g_assert (gi); - gi->generic_sharing_context = cfg->generic_sharing_context; + if (cfg->method->dynamic) + gi->generic_sharing_context = g_new0 (MonoGenericSharingContext, 1); + else + gi->generic_sharing_context = mono_domain_alloc0 (cfg->domain, sizeof (MonoGenericSharingContext)); + memcpy (gi->generic_sharing_context, cfg->generic_sharing_context, sizeof (MonoGenericSharingContext)); if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) || mini_method_get_context (method_to_compile)->method_inst || @@ -4065,6 +4161,10 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) info->stack_size = stack_size; } + if (cas_size) { + jinfo->has_cas_info = 1; + } + if (COMPILE_LLVM (cfg)) { if (num_clauses) memcpy (&jinfo->clauses [0], &cfg->llvm_ex_info [0], num_clauses * sizeof (MonoJitExceptionInfo)); @@ -4178,18 +4278,75 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile) } #endif +static MonoType* +get_gsharedvt_type (MonoType *t) +{ + MonoGenericParam *par = t->data.generic_param; + MonoType *res; + + /* + * Create an anonymous gparam with a different serial so normal gshared and gsharedvt methods have + * a different instantiation. + */ + g_assert (mono_generic_param_info (par)); + par = g_memdup (par, sizeof (MonoGenericParamFull)); + par->owner = NULL; + // FIXME: + par->image = mono_defaults.corlib; + par->serial = 1; + res = mono_metadata_type_dup (NULL, t); + res->data.generic_param = par; + + return res; +} + +static gboolean +is_gsharedvt_type (MonoType *t) +{ + return (t->type == MONO_TYPE_VAR || t->type == MONO_TYPE_MVAR) && t->data.generic_param->serial == 1; +} + +/* Return whenever METHOD is a gsharedvt method */ +static gboolean +is_gsharedvt_method (MonoMethod *method) +{ + MonoGenericContext *context; + MonoGenericInst *inst; + int i; + + if (!method->is_inflated) + return FALSE; + context = mono_method_get_context (method); + inst = context->class_inst; + if (inst) { + for (i = 0; i < inst->type_argc; ++i) + if (is_gsharedvt_type (inst->type_argv [i])) + return TRUE; + } + inst = context->method_inst; + if (inst) { + for (i = 0; i < inst->type_argc; ++i) + if (is_gsharedvt_type (inst->type_argv [i])) + return TRUE; + } + return FALSE; +} + /* - * mini_get_shared_method: + * mini_get_shared_method_full: * * Return the method which is actually compiled/registered when doing generic sharing. + * If ALL_VT is true, return the shared method belonging to an all-vtype instantiation. + * If IS_GSHAREDVT is true, treat METHOD as a gsharedvt method even if it fails some constraints. */ MonoMethod* -mini_get_shared_method (MonoMethod *method) +mini_get_shared_method_full (MonoMethod *method, gboolean all_vt, gboolean is_gsharedvt) { MonoGenericContext shared_context; MonoMethod *declaring_method, *res; int i; gboolean partial = FALSE; + gboolean gsharedvt = FALSE; if (method->is_generic || method->klass->generic_container) declaring_method = method; @@ -4201,12 +4358,15 @@ mini_get_shared_method (MonoMethod *method) else shared_context = declaring_method->klass->generic_container->context; - /* Handle partial sharing */ - if (method != declaring_method && method->is_inflated && !mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE)) { + /* Handle gsharedvt/partial sharing */ + if ((method != declaring_method && method->is_inflated && !mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE)) || + is_gsharedvt || mini_is_gsharedvt_sharable_method (method)) { MonoGenericContext *context = mono_method_get_context (method); MonoGenericInst *inst; MonoType **type_argv; + gsharedvt = is_gsharedvt || mini_is_gsharedvt_sharable_method (method); + /* * Create the shared context by replacing the ref type arguments with * type parameters, and keeping the rest. @@ -4216,8 +4376,10 @@ mini_get_shared_method (MonoMethod *method) if (inst) { type_argv = g_new0 (MonoType*, inst->type_argc); for (i = 0; i < inst->type_argc; ++i) { - if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR) + if (!all_vt && (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)) type_argv [i] = shared_context.class_inst->type_argv [i]; + else if (gsharedvt) + type_argv [i] = get_gsharedvt_type (shared_context.class_inst->type_argv [i]); else type_argv [i] = inst->type_argv [i]; } @@ -4230,8 +4392,10 @@ mini_get_shared_method (MonoMethod *method) if (inst) { type_argv = g_new0 (MonoType*, inst->type_argc); for (i = 0; i < inst->type_argc; ++i) { - if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR) + if (!all_vt && (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)) type_argv [i] = shared_context.method_inst->type_argv [i]; + else if (gsharedvt) + type_argv [i] = get_gsharedvt_type (shared_context.method_inst->type_argv [i]); else type_argv [i] = inst->type_argv [i]; } @@ -4249,6 +4413,54 @@ mini_get_shared_method (MonoMethod *method) return res; } +MonoMethod* +mini_get_shared_method (MonoMethod *method) +{ + return mini_get_shared_method_full (method, FALSE, FALSE); +} + +static void +mini_init_gsctx_full (MonoGenericContext *context, MonoGenericSharingContext *gsctx, gboolean all_vt) +{ + MonoGenericInst *inst; + int i; + + memset (gsctx, 0, sizeof (MonoGenericSharingContext)); + + if (context->class_inst) { + inst = context->class_inst; + gsctx->var_is_vt = g_new0 (gboolean, inst->type_argc); + + for (i = 0; i < inst->type_argc; ++i) { + MonoType *type = inst->type_argv [i]; + + if (!all_vt && (MONO_TYPE_IS_REFERENCE (type) || (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))) { + } else { + gsctx->var_is_vt [i] = TRUE; + } + } + } + if (context->method_inst) { + inst = context->method_inst; + gsctx->mvar_is_vt = g_new0 (gboolean, inst->type_argc); + + for (i = 0; i < inst->type_argc; ++i) { + MonoType *type = inst->type_argv [i]; + + if (!all_vt && (MONO_TYPE_IS_REFERENCE (type) || (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))) { + } else { + gsctx->mvar_is_vt [i] = TRUE; + } + } + } +} + +void +mini_init_gsctx (MonoGenericContext *context, MonoGenericSharingContext *gsctx) +{ + mini_init_gsctx_full (context, gsctx, FALSE); +} + #ifndef DISABLE_JIT /* * mini_method_compile: @@ -4274,11 +4486,12 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool gboolean deadce_has_run = FALSE; gboolean try_generic_shared, try_llvm = FALSE; MonoMethod *method_to_compile, *method_to_register; + gboolean method_is_gshared = FALSE; InterlockedIncrement (&mono_jit_stats.methods_compiled); if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION) mono_profiler_method_jit (method); - if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ()) + if (MONO_METHOD_COMPILE_BEGIN_ENABLED ()) MONO_PROBE_METHOD_COMPILE_BEGIN (method); if (compile_aot) @@ -4288,10 +4501,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool * FIXME: Remove the method->klass->generic_class limitation. */ try_generic_shared = mono_class_generic_sharing_enabled (method->klass) && - (opts & MONO_OPT_GSHARED) && ((method->is_generic || method->klass->generic_container) || (!method->klass->generic_class && mono_method_is_generic_sharable_impl (method, TRUE))); + (opts & MONO_OPT_GSHARED) && ((method->is_generic || method->klass->generic_container) || (!method->klass->generic_class && mono_method_is_generic_sharable_impl_full (method, TRUE, FALSE, FALSE))); else try_generic_shared = mono_class_generic_sharing_enabled (method->klass) && - (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method, FALSE); + (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE); if (opts & MONO_OPT_GSHARED) { if (try_generic_shared) @@ -4300,16 +4513,34 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool mono_stats.generics_unsharable_methods++; } + if (mini_is_gsharedvt_sharable_method (method)) { + if (!mono_debug_count ()) + try_generic_shared = FALSE; + if (compile_aot) + try_generic_shared = FALSE; + } + + if (is_gsharedvt_method (method)) { + /* We are AOTing a gshared method directly */ + method_is_gshared = TRUE; + g_assert (compile_aot); + try_generic_shared = TRUE; + } + #ifdef ENABLE_LLVM try_llvm = mono_use_llvm; #endif restart_compile: - if (try_generic_shared) { - method_to_compile = mini_get_shared_method (method); - g_assert (method_to_compile); - } else { + if (method_is_gshared) { method_to_compile = method; + } else { + if (try_generic_shared) { + method_to_compile = mini_get_shared_method (method); + g_assert (method_to_compile); + } else { + method_to_compile = method; + } } cfg = g_new0 (MonoCompile, 1); @@ -4328,18 +4559,40 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool cfg->explicit_null_checks = debug_options.explicit_null_checks; cfg->soft_breakpoints = debug_options.soft_breakpoints; if (try_generic_shared) - cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context; + cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->gsctx; cfg->compile_llvm = try_llvm; cfg->token_info_hash = g_hash_table_new (NULL, NULL); if (cfg->gen_seq_points) cfg->seq_points = g_ptr_array_new (); - if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container)) { + if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container || method_is_gshared)) { cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED; return cfg; } + if (cfg->generic_sharing_context && (mini_is_gsharedvt_sharable_method (method) || method_is_gshared)) { + MonoMethodInflated *inflated; + MonoGenericContext *context; + + g_assert (method->is_inflated); + inflated = (MonoMethodInflated*)method; + context = &inflated->context; + + // FIXME: Free the contents of gsctx if compilation fails + if (method_is_gshared) { + /* We are compiling a gsharedvt method directly */ + g_assert (compile_aot); + mini_init_gsctx_full (context, &cfg->gsctx, TRUE); + } else { + mini_init_gsctx (context, &cfg->gsctx); + } + + cfg->gsharedvt = TRUE; + // FIXME: + cfg->disable_llvm = TRUE; + } + if (cfg->generic_sharing_context) { method_to_register = method_to_compile; } else { @@ -4354,7 +4607,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD; cfg->exception_message = g_strdup (mono_error_get_message (&err)); mono_error_cleanup (&err); - if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ()) + if (MONO_METHOD_COMPILE_END_ENABLED ()) MONO_PROBE_METHOD_COMPILE_END (method, FALSE); return cfg; } @@ -4369,7 +4622,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM; cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name); } - if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ()) + if (MONO_METHOD_COMPILE_END_ENABLED ()) MONO_PROBE_METHOD_COMPILE_END (method, FALSE); return cfg; } @@ -4479,12 +4732,19 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool if (cfg->verbose_level > 0) { char *method_name; + + method_name = mono_method_full_name (method, TRUE); + g_print ("converting %s%s%smethod %s\n", COMPILE_LLVM (cfg) ? "llvm " : "", cfg->gsharedvt ? "gsharedvt " : "", (cfg->generic_sharing_context && !cfg->gsharedvt) ? "gshared " : "", method_name); + /* if (COMPILE_LLVM (cfg)) g_print ("converting llvm method %s\n", method_name = mono_method_full_name (method, TRUE)); + else if (cfg->gsharedvt) + g_print ("converting gsharedvt method %s\n", method_name = mono_method_full_name (method_to_compile, TRUE)); else if (cfg->generic_sharing_context) g_print ("converting shared method %s\n", method_name = mono_method_full_name (method_to_compile, TRUE)); else g_print ("converting method %s\n", method_name = mono_method_full_name (method, TRUE)); + */ g_free (method_name); } @@ -4573,7 +4833,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool if (i < 0) { if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) { if (compile_aot) { - if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ()) + if (MONO_METHOD_COMPILE_END_ENABLED ()) MONO_PROBE_METHOD_COMPILE_END (method, FALSE); return cfg; } @@ -4583,7 +4843,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool } g_assert (cfg->exception_type != MONO_EXCEPTION_GENERIC_SHARING_FAILED); - if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ()) + if (MONO_METHOD_COMPILE_END_ENABLED ()) MONO_PROBE_METHOD_COMPILE_END (method, FALSE); /* cfg contains the details of the failure, so let the caller cleanup */ return cfg; @@ -4706,7 +4966,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool /* after method_to_ir */ if (parts == 1) { - if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ()) + if (MONO_METHOD_COMPILE_END_ENABLED ()) MONO_PROBE_METHOD_COMPILE_END (method, TRUE); return cfg; } @@ -4743,7 +5003,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool /* after SSA translation */ if (parts == 2) { - if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ()) + if (MONO_METHOD_COMPILE_END_ENABLED ()) MONO_PROBE_METHOD_COMPILE_END (method, TRUE); return cfg; } @@ -4810,7 +5070,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool /* after SSA removal */ if (parts == 3) { - if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ()) + if (MONO_METHOD_COMPILE_END_ENABLED ()) MONO_PROBE_METHOD_COMPILE_END (method, TRUE); return cfg; } @@ -5031,9 +5291,16 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool mono_domain_unlock (cfg->domain); } +#if 0 + if (cfg->gsharedvt) + printf ("GSHAREDVT: %s\n", mono_method_full_name (cfg->method, TRUE)); +#endif + /* collect statistics */ +#ifndef DISABLE_PERFCOUNTERS mono_perfcounters->jit_methods++; mono_perfcounters->jit_bytes += header->code_size; +#endif mono_jit_stats.allocated_code_size += cfg->code_len; code_size_ratio = cfg->code_len; if (code_size_ratio > mono_jit_stats.biggest_method_size && mono_jit_stats.enabled) { @@ -5049,7 +5316,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool } mono_jit_stats.native_code_size += cfg->code_len; - if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ()) + if (MONO_METHOD_COMPILE_END_ENABLED ()) MONO_PROBE_METHOD_COMPILE_END (method, TRUE); return cfg; @@ -5102,7 +5369,7 @@ lookup_method_inner (MonoDomain *domain, MonoMethod *method) if (ji) return ji; - if (!mono_method_is_generic_sharable_impl (method, FALSE)) + if (!mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE)) return NULL; return mono_domain_lookup_shared_generic (domain, method); } @@ -5260,9 +5527,42 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in return NULL; } + if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) { + WrapperInfo *info = mono_marshal_get_wrapper_info (method); + + if (info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN || info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_OUT) { + static MonoTrampInfo *in_tinfo, *out_tinfo; + MonoTrampInfo *tinfo; + MonoJitInfo *jinfo; + gboolean is_in = info->subtype == WRAPPER_SUBTYPE_GSHAREDVT_IN; + + if (is_in && in_tinfo) + return in_tinfo->code; + else if (!is_in && out_tinfo) + return out_tinfo->code; + + /* + * This is a special wrapper whose body is implemented in assembly, like a trampoline. We use a wrapper so EH + * works. + * FIXME: The caller signature doesn't match the callee, which might cause problems on some platforms + */ + if (mono_aot_only) + mono_aot_get_trampoline_full (is_in ? "gsharedvt_trampoline" : "gsharedvt_out_trampoline", &tinfo); + else + mono_arch_get_gsharedvt_trampoline (&tinfo, FALSE); + jinfo = create_jit_info_for_trampoline (method, tinfo); + mono_jit_info_table_add (mono_get_root_domain (), jinfo); + if (is_in) + in_tinfo = tinfo; + else + out_tinfo = tinfo; + return tinfo->code; + } + } + if (mono_aot_only) { char *fullname = mono_method_full_name (method, TRUE); - char *msg = g_strdup_printf ("Attempting to JIT compile method '%s' while running with --aot-only.\n", fullname); + char *msg = g_strdup_printf ("Attempting to JIT compile method '%s' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.\n", fullname); *jit_ex = mono_get_exception_execution_engine (msg); g_free (fullname); @@ -5384,8 +5684,10 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in mono_domain_jit_code_hash_unlock (target_domain); code = cfg->native_code; - if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl (method, FALSE)) + if (cfg->generic_sharing_context && mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE, TRUE)) mono_stats.generics_shared_methods++; + if (cfg->gsharedvt) + mono_stats.gsharedvt_methods++; } else { mono_domain_jit_code_hash_unlock (target_domain); } @@ -5569,7 +5871,7 @@ static void invalidated_delegate_trampoline (char *desc) { g_error ("Unmanaged code called delegate of type %s which was already garbage collected.\n" - "See http://www.go-mono.com/delegate.html for an explanation and ways to fix this.", + "See http://www.mono-project.com/Diagnostic:Delegate for an explanation and ways to fix this.", desc); } #endif @@ -5764,8 +6066,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec } } - if (mono_method_needs_static_rgctx_invoke (method, FALSE)) - info->compiled_method = mono_create_static_rgctx_trampoline (method, info->compiled_method); + info->compiled_method = mini_add_method_trampoline (NULL, method, info->compiled_method, NULL, mono_method_needs_static_rgctx_invoke (method, FALSE)); } /* @@ -6344,7 +6645,7 @@ mini_init (const char *filename, const char *runtime_version) MonoRuntimeCallbacks callbacks; MonoThreadInfoRuntimeCallbacks ticallbacks; - MONO_PROBE_VES_INIT_BEGIN (); + MONO_VES_INIT_BEGIN (); #if defined(__linux__) && !defined(__native_client__) if (access ("/proc/self/maps", F_OK) != 0) { @@ -6357,6 +6658,11 @@ mini_init (const char *filename, const char *runtime_version) if (!default_opt_set) default_opt = mono_parse_default_optimizations (NULL); +#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED + if (mono_aot_only) + mono_set_generic_sharing_vt_supported (TRUE); +#endif + InitializeCriticalSection (&jit_mutex); #ifdef MONO_DEBUGGER_SUPPORTED @@ -6445,7 +6751,6 @@ mini_init (const char *filename, const char *runtime_version) g_thread_init (NULL); mono_native_tls_alloc (&mono_jit_tls_id, NULL); - setup_jit_tls_data ((gpointer)-1, mono_thread_abort); if (default_opt & MONO_OPT_AOT) mono_aot_init (); @@ -6538,6 +6843,11 @@ mini_init (const char *filename, const char *runtime_version) mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers", mono_runtime_install_handlers); +#ifdef PLATFORM_ANDROID + mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal", + mono_debugger_agent_unhandled_exception); +#endif + mono_create_helper_signatures (); register_jit_stats (); @@ -6720,6 +7030,7 @@ mini_init (const char *filename, const char *runtime_version) register_icall (mono_array_new_3, "mono_array_new_3", "object ptr int int int", FALSE); register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE); register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE); + register_icall (mono_object_tostring_gsharedvt, "mono_object_tostring_gsharedvt", "object ptr ptr ptr", TRUE); register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE); @@ -6756,7 +7067,7 @@ mini_init (const char *filename, const char *runtime_version) mono_profiler_runtime_initialized (); - MONO_PROBE_VES_INIT_END (); + MONO_VES_INIT_END (); return domain; } @@ -6790,6 +7101,7 @@ print_jit_stats (void) g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods); g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods); g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods); + g_print ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_methods); g_print ("Dynamic code allocs: %ld\n", mono_stats.dynamic_code_alloc_count); g_print ("Dynamic code bytes: %ld\n", mono_stats.dynamic_code_bytes_count); @@ -6809,10 +7121,6 @@ print_jit_stats (void) g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count); g_print ("Hazardous pointers: %ld\n", mono_stats.hazardous_pointer_count); - g_print ("Minor GC collections: %ld\n", mono_stats.minor_gc_count); - g_print ("Major GC collections: %ld\n", mono_stats.major_gc_count); - g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0); - g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0); if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) { g_print ("\nDecl security check : %ld\n", mono_jit_stats.cas_declsec_check); g_print ("LinkDemand (user) : %ld\n", mono_jit_stats.cas_linkdemand); @@ -6910,8 +7218,7 @@ void mono_set_defaults (int verbose_level, guint32 opts) { mini_verbose = verbose_level; - default_opt = opts; - default_opt_set = TRUE; + mono_set_optimizations (opts); } void @@ -6925,6 +7232,9 @@ mono_set_optimizations (guint32 opts) { default_opt = opts; default_opt_set = TRUE; +#ifdef MONO_ARCH_GSHAREDVT_SUPPORTED + mono_set_generic_sharing_vt_supported (mono_aot_only || ((default_opt & MONO_OPT_GSHAREDVT) != 0)); +#endif } void @@ -7029,3 +7339,71 @@ mono_cfg_set_exception (MonoCompile *cfg, int type) } #endif + +/* Dummy versions of some arch specific functions to avoid ifdefs at call sites */ + +#ifndef MONO_ARCH_GSHAREDVT_SUPPORTED + +gboolean +mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig) +{ + return FALSE; +} + +gpointer +mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) +{ + g_assert_not_reached (); + return NULL; +} + +#endif + +#ifdef DISABLE_JIT + +gpointer +mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpointer addr) +{ + g_assert_not_reached (); + return NULL; +} + +gpointer +mono_arch_get_gsharedvt_trampoline (MonoTrampInfo **info, gboolean aot) +{ + g_assert_not_reached (); + return NULL; +} + +#endif + +#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED) && !defined(MONOTOUCH) && !defined(MONO_EXTENSIONS) + +gboolean +mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig) +{ + return FALSE; +} + +gpointer +mono_arch_get_gsharedvt_call_info (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli) +{ + NOT_IMPLEMENTED; + return NULL; +} + +#endif