#include <mono/utils/mono-hwcap.h>
#include <mono/utils/dtrace.h>
#include <mono/utils/mono-signal-handler.h>
+#include <mono/utils/mono-threads.h>
#include "mini.h"
#include "mini-llvm.h"
gboolean mono_do_x86_stack_align = TRUE;
const char *mono_build_date;
gboolean mono_do_signal_chaining;
+gboolean mono_do_crash_chaining;
static gboolean mono_using_xdebug;
static int mini_verbose = 0;
copy->code_size = info->code_size;
copy->name = g_strdup (info->name);
- mono_loader_lock_if_inited ();
+ mono_jit_lock ();
tramp_infos = g_slist_prepend (tramp_infos, copy);
- mono_loader_unlock_if_inited ();
+ mono_jit_unlock ();
mono_save_trampoline_xdebug_info (info);
mono_tramp_info_free (info);
}
+static void
+mono_tramp_info_cleanup (void)
+{
+ GSList *l;
+
+ for (l = tramp_infos; l; l = l->next) {
+ MonoTrampInfo *info = l->data;
+
+ mono_tramp_info_free (info);
+ }
+ g_slist_free (tramp_infos);
+}
+
G_GNUC_UNUSED static void
break_count (void)
{
if (type->byref)
return OP_STORE_MEMBASE_REG;
+ type = mini_replace_type (type);
+
handle_enum:
switch (type->type) {
case MONO_TYPE_I1:
if (type->byref)
return OP_LOAD_MEMBASE;
- type = mono_type_get_underlying_type (type);
+ type = mini_replace_type (type);
switch (type->type) {
case MONO_TYPE_I1:
guint
mini_type_to_stind (MonoCompile* cfg, MonoType *type)
{
+ type = mini_replace_type (type);
+
if (cfg->generic_sharing_context && !type->byref) {
if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
if (mini_type_var_is_vt (cfg, type))
int num = cfg->num_varinfo;
gboolean regpair;
+ type = mini_replace_type (type);
+
if ((num + 1) >= cfg->varinfo_count) {
int orig_count = cfg->varinfo_count;
cfg->varinfo_count = cfg->varinfo_count ? (cfg->varinfo_count * 2) : 64;
if (type->byref) {
mono_mark_vreg_as_mp (cfg, vreg);
} else {
- MonoType *t = mini_type_get_underlying_type (NULL, type);
+ MonoType *t = mini_replace_type (type);
if ((MONO_TYPE_ISSTRUCT (t) && inst->klass->has_references) || mini_type_is_reference (cfg, t)) {
inst->flags |= MONO_INST_GC_TRACK;
mono_mark_vreg_as_ref (cfg, vreg);
mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
{
int dreg;
+ type = mini_replace_type (type);
if (mono_type_is_long (type))
dreg = mono_alloc_dreg (cfg, STACK_I8);
/*
* For JIT icalls implemented in C.
* NAME should be the same as the name of the C function whose address is FUNC.
+ * If SAVE is TRUE, no wrapper is generated. This is for perf critical icalls which
+ * can't throw exceptions.
*/
static void
register_icall (gpointer func, const char *name, const char *sigstr, gboolean save)
(*mono_get_lmf_addr ()) = lmf;
}
+MonoJitTlsData*
+mono_get_jit_tls (void)
+{
+ return mono_native_tls_get_value (mono_jit_tls_id);
+}
+
static void
mono_set_jit_tls (MonoJitTlsData *jit_tls)
{
+ MonoThreadInfo *info;
+
mono_native_tls_set_value (mono_jit_tls_id, jit_tls);
#ifdef MONO_HAVE_FAST_TLS
MONO_FAST_TLS_SET (mono_jit_tls, jit_tls);
#endif
+
+ /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
+ info = mono_thread_info_current ();
+ if (info)
+ mono_thread_info_tls_set (info, TLS_KEY_JIT_TLS, jit_tls);
}
static void
mono_set_lmf_addr (gpointer lmf_addr)
{
+ MonoThreadInfo *info;
+
#ifdef MONO_HAVE_FAST_TLS
MONO_FAST_TLS_SET (mono_lmf_addr, lmf_addr);
#endif
+
+ /* Save it into MonoThreadInfo so it can be accessed by mono_thread_state_init_from_handle () */
+ info = mono_thread_info_current ();
+ if (info)
+ mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
}
/*
offset = mono_thread_get_tls_offset ();
break;
case TLS_KEY_JIT_TLS:
+#ifdef HOST_WIN32
+ offset = mono_get_jit_tls_key ();
+ /* Only 64 tls entries can be accessed using inline code */
+ if (offset >= 64)
+ offset = -1;
+#else
offset = mono_get_jit_tls_offset ();
+#endif
break;
case TLS_KEY_DOMAIN:
offset = mono_domain_get_tls_offset ();
g_assert (offset != -1);
break;
}
+
return offset;
}
return ins;
}
+gboolean
+mini_tls_get_supported (MonoCompile *cfg, MonoTlsKey key)
+{
+ if (!MONO_ARCH_HAVE_TLS_GET)
+ return FALSE;
+
+ if (cfg->compile_aot)
+ return ARCH_HAVE_TLS_GET_REG;
+ else
+ return mini_get_tls_offset (key) != -1;
+}
+
MonoInst*
mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
{
void
mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
{
- MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
+ MonoJumpInfo *ji = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfo));
ji->ip.i = ip;
ji->type = type;
void
mono_add_patch_info_rel (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target, int relocation)
{
- MonoJumpInfo *ji = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfo));
+ MonoJumpInfo *ji = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfo));
ji->ip.i = ip;
ji->type = type;
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_DELEGATE_TRAMPOLINE:
+ res->data.del_tramp = mono_mempool_alloc0 (mp, sizeof (MonoClassMethodPair));
+ memcpy (res->data.del_tramp, patch_info->data.del_tramp, sizeof (MonoClassMethodPair));
+ 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));
info = mono_mempool_alloc (mp, sizeof (MonoGSharedVtMethodInfo));
res->data.gsharedvt_method = info;
memcpy (info, oinfo, sizeof (MonoGSharedVtMethodInfo));
- info->entries = g_ptr_array_new ();
- if (oinfo->entries) {
- for (i = 0; i < oinfo->entries->len; ++i) {
- MonoRuntimeGenericContextInfoTemplate *otemplate = g_ptr_array_index (oinfo->entries, i);
- MonoRuntimeGenericContextInfoTemplate *template = mono_mempool_alloc0 (mp, sizeof (MonoRuntimeGenericContextInfoTemplate));
+ info->entries = mono_mempool_alloc (mp, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
+ for (i = 0; i < oinfo->num_entries; ++i) {
+ MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
+ MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
- memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
- g_ptr_array_add (info->entries, template);
- }
+ memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
}
//info->locals_types = mono_mempool_alloc0 (mp, info->nlocals * sizeof (MonoType*));
//memcpy (info->locals_types, oinfo->locals_types, info->nlocals * sizeof (MonoType*));
case MONO_PATCH_INFO_SFLDA:
case MONO_PATCH_INFO_SEQ_POINT_INFO:
case MONO_PATCH_INFO_METHOD_RGCTX:
- case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
case MONO_PATCH_INFO_SIGNATURE:
case MONO_PATCH_INFO_TLS_OFFSET:
+ case MONO_PATCH_INFO_METHOD_CODE_SLOT:
return (ji->type << 8) | (gssize)ji->data.target;
case MONO_PATCH_INFO_GSHAREDVT_CALL:
return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
case MONO_PATCH_INFO_OBJC_SELECTOR_REF:
/* Hash on the selector name */
return g_str_hash (ji->data.target);
+ case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
+ return (ji->type << 8) | (gsize)ji->data.del_tramp->klass | (gsize)ji->data.del_tramp->method;
default:
printf ("info type: %d\n", ji->type);
mono_print_ji (ji); printf ("\n");
}
case MONO_PATCH_INFO_GSHAREDVT_METHOD:
return ji1->data.gsharedvt_method->method == ji2->data.gsharedvt_method->method;
+ case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
+ return ji1->data.del_tramp->klass == ji2->data.del_tramp->klass && ji1->data.del_tramp->method == ji2->data.del_tramp->method;
default:
if (ji1->data.target != ji2->data.target)
return 0;
}
#endif
break;
+ case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
+ gpointer code_slot;
+
+ mono_domain_lock (domain);
+ if (!domain_jit_info (domain)->method_code_hash)
+ domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
+ code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
+ if (!code_slot) {
+ code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
+ g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
+ }
+ mono_domain_unlock (domain);
+ target = code_slot;
+ break;
+ }
case MONO_PATCH_INFO_SWITCH: {
gpointer *jump_table;
int i;
target = mono_create_class_init_trampoline (vtable);
break;
}
- case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
- target = mono_create_delegate_trampoline (domain, patch_info->data.klass);
+ case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
+ MonoClassMethodPair *del_tramp = patch_info->data.del_tramp;
+
+ target = mono_create_delegate_trampoline_with_method (domain, del_tramp->klass, del_tramp->method);
break;
+ }
case MONO_PATCH_INFO_SFLDA: {
MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
/* Make a copy into the domain mempool */
info = g_malloc0 (sizeof (MonoGSharedVtMethodInfo)); //mono_domain_alloc0 (domain, sizeof (MonoGSharedVtMethodInfo));
info->method = oinfo->method;
- info->entries = g_ptr_array_new ();
- for (i = 0; i < oinfo->entries->len; ++i) {
- MonoRuntimeGenericContextInfoTemplate *otemplate = g_ptr_array_index (oinfo->entries, i);
- MonoRuntimeGenericContextInfoTemplate *template = g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate));
+ info->num_entries = oinfo->num_entries;
+ info->entries = g_malloc0 (sizeof (MonoRuntimeGenericContextInfoTemplate) * info->num_entries);
+ for (i = 0; i < oinfo->num_entries; ++i) {
+ MonoRuntimeGenericContextInfoTemplate *otemplate = &oinfo->entries [i];
+ MonoRuntimeGenericContextInfoTemplate *template = &info->entries [i];
memcpy (template, otemplate, sizeof (MonoRuntimeGenericContextInfoTemplate));
- g_ptr_array_add (info->entries, template);
}
slot = mono_method_lookup_or_register_info (entry->method, entry->in_mrgctx, info, entry->info_type, mono_method_get_context (entry->method));
break;
target = (gpointer) (size_t) mono_jit_tls_id;
break;
}
- case MONO_PATCH_INFO_TLS_OFFSET:
- target = GINT_TO_POINTER (mini_get_tls_offset (GPOINTER_TO_INT (patch_info->data.target)));
+ case MONO_PATCH_INFO_TLS_OFFSET: {
+ int offset;
+
+ offset = mini_get_tls_offset (GPOINTER_TO_INT (patch_info->data.target));
+#ifdef MONO_ARCH_HAVE_TRANSLATE_TLS_OFFSET
+ offset = mono_arch_translate_tls_offset (offset);
+#endif
+ target = GINT_TO_POINTER (offset);
break;
+ }
case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
target = NULL;
break;
jinfo->code_size = info->code_size;
jinfo->used_regs = mono_cache_unwind_info (uw_info, info_len);
+ if (!info->uw_info)
+ g_free (uw_info);
+
return jinfo;
}
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));
+ mini_init_gsctx (cfg->method->dynamic ? NULL : cfg->domain, NULL, cfg->gsctx_context, gi->generic_sharing_context);
if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
mini_method_get_context (method_to_compile)->method_inst ||
MonoExceptionClause *ec = &header->clauses [i];
MonoJitExceptionInfo *ei = &jinfo->clauses [i];
MonoBasicBlock *tblock;
- MonoInst *exvar;
+ MonoInst *exvar, *spvar;
ei->flags = ec->flags;
- exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
- ei->exvar_offset = exvar ? exvar->inst_offset : 0;
+ /*
+ * The spvars are needed by mono_arch_install_handler_block_guard ().
+ */
+ if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
+ int region;
+
+ region = ((i + 1) << 8) | MONO_REGION_FINALLY | ec->flags;
+ spvar = mono_find_spvar_for_region (cfg, region);
+ g_assert (spvar);
+ ei->exvar_offset = spvar->inst_offset;
+ } else {
+ exvar = mono_find_exvar_for_offset (cfg, ec->handler_offset);
+ ei->exvar_offset = exvar ? exvar->inst_offset : 0;
+ }
if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
tblock = cfg->cil_offset_to_bb [ec->data.filter_offset];
get_gsharedvt_type (MonoType *t)
{
MonoGenericParam *par = t->data.generic_param;
+ MonoGenericParam *copy;
MonoType *res;
+ MonoImage *image = NULL;
/*
* 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;
+ if (par->owner) {
+ image = par->owner->image;
+
+ mono_image_lock (image);
+ if (!image->gsharedvt_types)
+ image->gsharedvt_types = g_hash_table_new (NULL, NULL);
+ res = g_hash_table_lookup (image->gsharedvt_types, par);
+ mono_image_unlock (image);
+ if (res)
+ return res;
+ copy = mono_image_alloc0 (image, sizeof (MonoGenericParamFull));
+ memcpy (copy, par, sizeof (MonoGenericParamFull));
+ } else {
+ copy = g_memdup (par, sizeof (MonoGenericParamFull));
+ }
+ copy->owner = NULL;
// FIXME:
- par->image = mono_defaults.corlib;
- par->serial = 1;
+ copy->image = mono_defaults.corlib;
+ copy->serial = 1;
res = mono_metadata_type_dup (NULL, t);
- res->data.generic_param = par;
+ res->data.generic_param = copy;
+
+ if (par->owner) {
+ mono_image_lock (image);
+ /* Duplicates are ok */
+ g_hash_table_insert (image->gsharedvt_types, par, res);
+ mono_image_unlock (image);
+ }
return res;
}
}
void
-mini_init_gsctx (MonoGenericContext *context, MonoGenericSharingContext *gsctx)
+mini_init_gsctx (MonoDomain *domain, MonoMemPool *mp, MonoGenericContext *context, MonoGenericSharingContext *gsctx)
{
MonoGenericInst *inst;
int i;
memset (gsctx, 0, sizeof (MonoGenericSharingContext));
- if (context->class_inst) {
+ if (context && context->class_inst) {
inst = context->class_inst;
- gsctx->var_is_vt = g_new0 (gboolean, inst->type_argc);
+ if (domain)
+ gsctx->var_is_vt = mono_domain_alloc0 (domain, sizeof (gboolean) * inst->type_argc);
+ else if (mp)
+ gsctx->var_is_vt = mono_mempool_alloc0 (mp, sizeof (gboolean) * inst->type_argc);
+ else
+ gsctx->var_is_vt = g_new0 (gboolean, inst->type_argc);
for (i = 0; i < inst->type_argc; ++i) {
MonoType *type = inst->type_argv [i];
gsctx->var_is_vt [i] = TRUE;
}
}
- if (context->method_inst) {
+ if (context && context->method_inst) {
inst = context->method_inst;
- gsctx->mvar_is_vt = g_new0 (gboolean, inst->type_argc);
+ if (domain)
+ gsctx->mvar_is_vt = mono_domain_alloc0 (domain, sizeof (gboolean) * inst->type_argc);
+ else if (mp)
+ gsctx->mvar_is_vt = mono_mempool_alloc0 (mp, sizeof (gboolean) * inst->type_argc);
+ else
+ gsctx->mvar_is_vt = g_new0 (gboolean, inst->type_argc);
for (i = 0; i < inst->type_argc; ++i) {
MonoType *type = inst->type_argv [i];
* @method: the method to compile
* @opts: the optimization flags to use
* @domain: the domain where the method will be compiled in
- * @run_cctors: whether we should run type ctors if possible
- * @compile_aot: whether this is an AOT compilation
+ * @flags: compilation flags
* @parts: debug flag
*
* Returns: a MonoCompile* pointer. Caller must check the exception_type
* field in the returned struct to see if compilation succeded.
*/
MonoCompile*
-mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
+mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFlags flags, int parts)
{
MonoMethodHeader *header;
MonoMethodSignature *sig;
gboolean try_generic_shared, try_llvm = FALSE;
MonoMethod *method_to_compile, *method_to_register;
gboolean method_is_gshared = FALSE;
+ gboolean run_cctors = (flags & JIT_FLAG_RUN_CCTORS) ? 1 : 0;
+ gboolean compile_aot = (flags & JIT_FLAG_AOT) ? 1 : 0;
+ gboolean full_aot = (flags & JIT_FLAG_FULL_AOT) ? 1 : 0;
InterlockedIncrement (&mono_jit_stats.methods_compiled);
if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
cfg->domain = domain;
cfg->verbose_level = mini_verbose;
cfg->compile_aot = compile_aot;
+ cfg->full_aot = full_aot;
cfg->skip_visibility = method->skip_visibility;
cfg->orig_method = method;
cfg->gen_seq_points = debug_options.gen_seq_points;
cfg->explicit_null_checks = debug_options.explicit_null_checks;
cfg->soft_breakpoints = debug_options.soft_breakpoints;
+ cfg->check_pinvoke_callconv = debug_options.check_pinvoke_callconv;
if (try_generic_shared)
cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->gsctx;
cfg->compile_llvm = try_llvm;
MonoMethodInflated *inflated;
MonoGenericContext *context;
- // FIXME: Free the contents of gsctx if compilation fails
if (method_is_gshared) {
g_assert (method->is_inflated);
inflated = (MonoMethodInflated*)method;
context = &inflated->context;
}
- mini_init_gsctx (context, &cfg->gsctx);
+ mini_init_gsctx (NULL, cfg->mempool, context, &cfg->gsctx);
+ cfg->gsctx_context = context;
cfg->gsharedvt = TRUE;
// FIXME:
#else
MonoCompile*
-mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
+mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFlags flags, int parts)
{
g_assert_not_reached ();
return NULL;
#endif /* DISABLE_JIT */
-MonoJitInfo*
-mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *method)
+/*
+ * LOCKING: Acquires the jit code hash lock.
+ */
+static MonoJitInfo*
+lookup_method_inner (MonoDomain *domain, MonoMethod *method, MonoMethod *shared)
{
+ MonoJitInfo *ji;
static gboolean inited = FALSE;
static int lookups = 0;
static int failed_lookups = 0;
- MonoJitInfo *ji;
- ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, mini_get_shared_method (method));
- if (ji && !ji->has_generic_jit_info)
- ji = NULL;
+ mono_domain_jit_code_hash_lock (domain);
+ ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
+ if (!ji && shared) {
+ /* Try generic sharing */
+ ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, shared);
+ if (ji && !ji->has_generic_jit_info)
+ ji = NULL;
+ if (!inited) {
+ mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
+ mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
+ inited = TRUE;
+ }
- if (!inited) {
- mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
- mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
- inited = TRUE;
+ ++lookups;
+ if (!ji)
+ ++failed_lookups;
}
-
- ++lookups;
- if (!ji)
- ++failed_lookups;
+ mono_domain_jit_code_hash_unlock (domain);
return ji;
}
-/*
- * LOCKING: Assumes domain->jit_code_hash_lock is held.
- */
-static MonoJitInfo*
-lookup_method_inner (MonoDomain *domain, MonoMethod *method)
-{
- MonoJitInfo *ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, method);
-
- if (ji)
- return ji;
-
- if (!mono_method_is_generic_sharable (method, FALSE))
- return NULL;
- return mono_domain_lookup_shared_generic (domain, method);
-}
-
static MonoJitInfo*
lookup_method (MonoDomain *domain, MonoMethod *method)
{
- MonoJitInfo *info;
+ MonoJitInfo *ji;
+ MonoMethod *shared;
- mono_loader_lock (); /*FIXME lookup_method_inner acquired it*/
- mono_domain_jit_code_hash_lock (domain);
- info = lookup_method_inner (domain, method);
- mono_domain_jit_code_hash_unlock (domain);
- mono_loader_unlock ();
+ ji = lookup_method_inner (domain, method, NULL);
- return info;
+ if (!ji) {
+ if (!mono_method_is_generic_sharable (method, FALSE))
+ return NULL;
+ shared = mini_get_shared_method (method);
+ ji = lookup_method_inner (domain, method, shared);
+ }
+
+ return ji;
}
#if ENABLE_JIT_MAP
MonoException *ex = NULL;
guint32 prof_options;
GTimer *jit_timer;
- MonoMethod *prof_method;
+ MonoMethod *prof_method, *shared;
#ifdef MONO_USE_AOT_COMPILER
if (opt & MONO_OPT_AOT) {
else
mono_lookup_pinvoke_call (method, NULL, NULL);
}
- nm = mono_marshal_get_native_wrapper (method, check_for_pending_exc, FALSE);
+ nm = mono_marshal_get_native_wrapper (method, check_for_pending_exc, mono_aot_only);
code = mono_get_addr_from_ftnptr (mono_compile_method (nm));
jinfo = mono_jit_info_table_find (target_domain, code);
if (!jinfo)
jit_timer = g_timer_new ();
- cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
+ cfg = mini_method_compile (method, opt, target_domain, JIT_FLAG_RUN_CCTORS, 0);
prof_method = cfg->method;
g_timer_stop (jit_timer);
return NULL;
}
- mono_loader_lock (); /*FIXME lookup_method_inner requires the loader lock*/
+ if (mono_method_is_generic_sharable (method, FALSE))
+ shared = mini_get_shared_method (method);
+ else
+ shared = NULL;
+
+ /*
+ * FIXME: lookup_method_inner requires the loader lock.
+ * FIXME: This is no longer true, can this be dropped ?
+ */
+ mono_loader_lock ();
mono_domain_lock (target_domain);
/* Check if some other thread already did the job. In this case, we can
mono_domain_jit_code_hash_lock (target_domain);
- info = lookup_method_inner (target_domain, method);
+ info = lookup_method_inner (target_domain, method, shared);
if (info) {
/* We can't use a domain specific method in another domain */
if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
#endif
if (!ji) {
- if (mono_chain_signal (SIG_HANDLER_PARAMS))
+ if (!mono_do_crash_chaining && mono_chain_signal (SIG_HANDLER_PARAMS))
return;
mono_handle_native_sigsegv (SIGSEGV, ctx);
+ if (mono_do_crash_chaining)
+ mono_chain_signal (SIG_HANDLER_PARAMS);
}
mono_arch_handle_exception (ctx, exc);
/* The thread might no be registered with the runtime */
if (!mono_domain_get () || !jit_tls) {
- if (mono_chain_signal (SIG_HANDLER_PARAMS))
+ if (!mono_do_crash_chaining && mono_chain_signal (SIG_HANDLER_PARAMS))
return;
mono_handle_native_sigsegv (SIGSEGV, ctx);
+ if (mono_do_crash_chaining)
+ mono_chain_signal (SIG_HANDLER_PARAMS);
}
ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
#else
if (!ji) {
- if (mono_chain_signal (SIG_HANDLER_PARAMS))
+ if (!mono_do_crash_chaining && mono_chain_signal (SIG_HANDLER_PARAMS))
return;
mono_handle_native_sigsegv (SIGSEGV, ctx);
+
+ if (mono_do_crash_chaining)
+ mono_chain_signal (SIG_HANDLER_PARAMS);
}
mono_arch_handle_exception (ctx, NULL);
debug_options.no_gdb_backtrace = TRUE;
else if (!strcmp (arg, "suspend-on-sigsegv"))
debug_options.suspend_on_sigsegv = TRUE;
+ else if (!strcmp (arg, "suspend-on-exception"))
+ debug_options.suspend_on_exception = TRUE;
else if (!strcmp (arg, "suspend-on-unhandled"))
debug_options.suspend_on_unhandled = TRUE;
else if (!strcmp (arg, "dont-free-domains"))
debug_options.better_cast_details = TRUE;
else if (!strcmp (arg, "soft-breakpoints"))
debug_options.soft_breakpoints = TRUE;
+ else if (!strcmp (arg, "check-pinvoke-callconv"))
+ debug_options.check_pinvoke_callconv = TRUE;
+ else if (!strcmp (arg, "debug-domain-unload"))
+ mono_enable_debug_domain_unload (TRUE);
else {
fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
- fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'suspend-on-unhandled', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'init-stacks'\n");
+ fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'init-stacks', 'check-pinvoke-callconv', 'debug-domain-unload'\n");
exit (1);
}
}
static void runtime_invoke_info_free (gpointer value);
static void seq_point_info_free (gpointer value);
-
+
+static gint
+class_method_pair_equal (gconstpointer ka, gconstpointer kb)
+{
+ const MonoClassMethodPair *apair = ka;
+ const MonoClassMethodPair *bpair = kb;
+
+ return apair->klass == bpair->klass && apair->method == bpair->method ? 1 : 0;
+}
+
+static guint
+class_method_pair_hash (gconstpointer data)
+{
+ const MonoClassMethodPair *pair = data;
+
+ return (gsize)pair->klass ^ (gsize)pair->method;
+}
+
static void
mini_create_jit_domain_info (MonoDomain *domain)
{
info->class_init_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
info->jump_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
info->jit_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
- info->delegate_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+ info->delegate_trampoline_hash = g_hash_table_new (class_method_pair_hash, class_method_pair_equal);
info->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
info->runtime_invoke_hash = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, seq_point_info_free);
g_slist_free (jlist->list);
}
+static void
+delete_got_slot_list (gpointer key, gpointer value, gpointer user_data)
+{
+ GSList *list = value;
+ g_slist_free (list);
+}
+
static void
dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
{
g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
g_hash_table_destroy (info->jump_target_hash);
if (info->jump_target_got_slot_hash) {
- g_hash_table_foreach (info->jump_target_got_slot_hash, delete_jump_list, NULL);
+ g_hash_table_foreach (info->jump_target_got_slot_hash, delete_got_slot_list, NULL);
g_hash_table_destroy (info->jump_target_got_slot_hash);
}
if (info->dynamic_code_hash) {
mono_debugger_agent_free_domain_info (domain);
if (info->gsharedvt_arg_tramp_hash)
g_hash_table_destroy (info->gsharedvt_arg_tramp_hash);
+#ifdef ENABLE_LLVM
+ mono_llvm_free_domain_info (domain);
+#endif
g_free (domain->runtime_info);
domain->runtime_info = NULL;
}
#endif
+ InitializeCriticalSection (&jit_mutex);
+
/* Happens when using the embedding interface */
if (!default_opt_set)
default_opt = mono_parse_default_optimizations (NULL);
mono_set_generic_sharing_vt_supported (TRUE);
#endif
- InitializeCriticalSection (&jit_mutex);
-
#ifdef MONO_HAVE_FAST_TLS
MONO_FAST_TLS_INIT (mono_jit_tls);
MONO_FAST_TLS_INIT (mono_lmf_addr);
/*Init arch tls information only after the metadata side is inited to make sure we see dynamic appdomain tls keys*/
mono_arch_finish_init ();
+ mono_icall_init ();
+
/* This must come after mono_init () in the aot-only case */
mono_exceptions_init ();
- mono_icall_init ();
-
/* This should come after mono_init () too */
mini_gc_init ();
#if SIZEOF_REGISTER == 4
register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
+#else
+ register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
#endif
/* other jit icalls */
register_icall (mono_array_new_4, "mono_array_new_4", "object ptr int 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_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", TRUE);
+ register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);
#endif
#ifdef TARGET_IOS
- register_icall (pthread_getspecific, "pthread_getspecific", NULL, TRUE);
+ register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
#endif
mono_generic_sharing_init ();
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);
- g_print ("Dynamic code frees: %ld\n", mono_stats.dynamic_code_frees_count);
-
g_print ("IMT tables size: %ld\n", mono_stats.imt_tables_size);
g_print ("IMT number of tables: %ld\n", mono_stats.imt_number_of_tables);
g_print ("IMT number of methods: %ld\n", mono_stats.imt_number_of_methods);
g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
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);
if (mono_security_cas_enabled ()) {
g_print ("\nDecl security check : %ld\n", mono_jit_stats.cas_declsec_check);
g_print ("LinkDemand (user) : %ld\n", mono_jit_stats.cas_linkdemand);
g_free (emul_opcode_opcodes);
g_free (vtable_trampolines);
+ mono_tramp_info_cleanup ();
+
mono_arch_cleanup ();
mono_generic_sharing_cleanup ();
#endif
-#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED) && !defined(MONOTOUCH) && !defined(MONO_EXTENSIONS)
+#ifndef MONO_ARCH_HAVE_OPCODE_SUPPORTED
+
+gboolean
+mono_arch_opcode_supported (int opcode)
+{
+ return TRUE;
+}
+
+#endif
+
+#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED) && !defined(ENABLE_GSHAREDVT)
gboolean
mono_arch_gsharedvt_sig_supported (MonoMethodSignature *sig)
return mono_arch_jumptable_entry_from_code (code_ptr);
}
#endif
+
+/*
+ * mini_replace_type:
+ *
+ * Replace the type used in the metadata stream with what the JIT will actually use during compilation.
+*/
+MonoType*
+mini_replace_type (MonoType *type)
+{
+ type = mono_type_get_underlying_type (type);
+ return mini_native_type_replace_type (type);
+}