#include <sys/time.h>
#endif
-#ifdef HAVE_VALGRIND_MEMCHECK_H
-#include <valgrind/memcheck.h>
-#endif
+#include <mono/utils/memcheck.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/loader.h>
MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL;
+MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL;
static guint32 default_opt = 0;
static gboolean default_opt_set = FALSE;
static int methods_with_llvm, methods_without_llvm;
#endif
+/*
+ * This flag controls whenever the runtime uses LLVM compiled code.
+ * Enabling this causes different/slower code paths to be used, which is why it
+ * defaults to FALSE if ENABLE_LLVM is not defined, i.e. the runtime is only capable of
+ * running AOT code compiled by LLVM.
+ * Changes when this flag is set include:
+ * - a per method vtable trampoline is used to handle virtual calls, instead of only
+ * one trampoline.
+ * - fast generic virtual calls are not supported.
+ */
+#ifdef ENABLE_LLVM
+gboolean mono_use_llvm = TRUE;
+#else
+gboolean mono_use_llvm = FALSE;
+#endif
+
#define mono_jit_lock() EnterCriticalSection (&jit_mutex)
#define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
static CRITICAL_SECTION jit_mutex;
gboolean
mono_running_on_valgrind (void)
{
-#ifdef HAVE_VALGRIND_MEMCHECK_H
- if (RUNNING_ON_VALGRIND){
+ if (RUNNING_ON_VALGRIND){
#ifdef VALGRIND_JIT_REGISTER_MAP
- valgrind_register = TRUE;
+ valgrind_register = TRUE;
#endif
- return TRUE;
- } else
- return FALSE;
-#else
+ return TRUE;
+ } else
return FALSE;
-#endif
}
typedef struct {
char *method;
MonoDebugSourceLocation *source;
MonoDomain *domain = mono_domain_get ();
+ MonoDomain *target_domain = mono_domain_get ();
FindTrampUserData user_data;
- ji = mono_jit_info_table_find (domain, ip);
+ ji = mini_jit_info_table_find (domain, ip, &target_domain);
if (!ji) {
user_data.ip = ip;
user_data.method = NULL;
return;
}
method = mono_method_full_name (ji->method, TRUE);
- source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
+ 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, domain, domain->friendly_name);
+ 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);
if (source)
g_print ("%s:%d\n", source->source_file, source->row);
return -1;
}
-MonoInst *
-mono_find_spvar_for_region (MonoCompile *cfg, int region)
+/*
+ * mono_get_block_region_notry:
+ *
+ * Return the region corresponding to REGION, ignoring try clauses nested inside
+ * finally clauses.
+ */
+int
+mono_get_block_region_notry (MonoCompile *cfg, int region)
{
if ((region & (0xf << 4)) == MONO_REGION_TRY) {
MonoMethodHeader *header = mono_method_get_header (cfg->method);
region = mono_find_block_region_notry (cfg, header->clauses [clause_index].try_offset);
}
- return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
+ return region;
}
-static MonoInst *
-mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
+MonoInst *
+mono_find_spvar_for_region (MonoCompile *cfg, int region)
{
- return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
+ region = mono_get_block_region_notry (cfg, region);
+
+ return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
}
static void
if (type->byref)
return OP_LOAD_MEMBASE;
- switch (mono_type_get_underlying_type (type)->type) {
+ type = mono_type_get_underlying_type (type);
+
+ switch (type->type) {
case MONO_TYPE_I1:
return OP_LOADI1_MEMBASE;
case MONO_TYPE_U1:
void
mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index) {
memset (dest, 0, sizeof (MonoInst));
- dest->ssa_op = MONO_SSA_LOAD;
dest->inst_i0 = cfg->varinfo [var_index];
dest->opcode = mini_type_to_ldind (cfg, dest->inst_i0->inst_vtype);
type_to_eval_stack_type (cfg, dest->inst_i0->inst_vtype, dest);
res->call_convention = MONO_CALL_VARARG;
#endif
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
res->call_convention = MONO_CALL_C;
#endif
return FALSE;
}
+/*Returns true is something went wrong*/
+static gboolean
+mono_compile_is_broken (MonoCompile *cfg)
+{
+ MonoMethod *method = cfg->method;
+ MonoMethod *method_definition = method;
+ gboolean dont_verify = mini_assembly_can_skip_verification (cfg->domain, method);
+ dont_verify |= method->klass->image->assembly->corlib_internal;
+
+ while (method_definition->is_inflated) {
+ MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
+ method_definition = imethod->declaring;
+ }
+
+ return !dont_verify && mini_method_verify (cfg, method_definition);
+}
+
static void
create_helper_signature (void)
{
helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
+ helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
}
static gconstpointer
size = mono_type_size (inst->inst_vtype, &ialign);
align = ialign;
+
+ if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (inst->inst_vtype)))
+ align = 16;
}
t = mono_type_get_underlying_type (inst->inst_vtype);
* efficient copying (and to work around the fact that OP_MEMCPY
* and OP_MEMSET ignores alignment).
*/
- if (MONO_TYPE_ISSTRUCT (t))
- align = MAX (sizeof (gpointer), mono_class_min_align (mono_class_from_mono_type (t)));
+ if (MONO_TYPE_ISSTRUCT (t)) {
+ align = MAX (align, sizeof (gpointer));
+ align = MAX (align, mono_class_min_align (mono_class_from_mono_type (t)));
+ }
if (backward) {
offset += size;
size = mono_type_size (inst->inst_vtype, &ialign);
align = ialign;
+
+ if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (inst->inst_vtype)))
+ align = 16;
}
t = mono_type_get_underlying_type (inst->inst_vtype);
* and OP_MEMSET ignores alignment).
*/
if (MONO_TYPE_ISSTRUCT (t)) {
- align = MAX (sizeof (gpointer), mono_class_min_align (mono_class_from_mono_type (t)));
+ align = MAX (align, sizeof (gpointer));
+ align = MAX (align, mono_class_min_align (mono_class_from_mono_type (t)));
/*
* Align the size too so the code generated for passing vtypes in
* registers doesn't overwrite random locals.
switch (patch_info->type) {
case MONO_PATCH_INFO_BB:
- g_assert (patch_info->data.bb->native_offset);
+ /*
+ * FIXME: This could be hit for methods without a prolog. Should use -1
+ * but too much code depends on a 0 initial value.
+ */
+ //g_assert (patch_info->data.bb->native_offset);
target = patch_info->data.bb->native_offset + code;
break;
case MONO_PATCH_INFO_ABS:
target = mono_arch_get_seq_point_info (domain, code);
break;
#endif
+ case MONO_PATCH_INFO_LLVM_IMT_TRAMPOLINE:
+#ifdef MONO_ARCH_LLVM_SUPPORTED
+ g_assert (mono_use_llvm);
+ target = mono_create_llvm_imt_trampoline (domain, patch_info->data.imt_tramp->method, patch_info->data.imt_tramp->vt_offset);
+#else
+ g_assert_not_reached ();
+#endif
+ break;
default:
g_assert_not_reached ();
}
return (gpointer)target;
}
+void
+mono_add_seq_point (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, int native_offset)
+{
+ ins->inst_offset = native_offset;
+ g_ptr_array_add (cfg->seq_points, ins);
+ bb->seq_points = g_slist_prepend_mempool (cfg->mempool, bb->seq_points, ins);
+ bb->last_seq_point = ins;
+}
+
static void
mono_compile_create_vars (MonoCompile *cfg)
{
}
}
+static void
+mono_save_seq_point_info (MonoCompile *cfg)
+{
+ MonoBasicBlock *bb, *in_bb;
+ GSList *bb_seq_points, *l;
+ MonoInst *last;
+ MonoDomain *domain = cfg->domain;
+ int i;
+ MonoSeqPointInfo *info;
+ GSList **next;
+
+ if (!cfg->seq_points)
+ return;
+
+ info = g_malloc0 (sizeof (MonoSeqPointInfo) + (cfg->seq_points->len - MONO_ZERO_LEN_ARRAY) * sizeof (SeqPoint));
+ info->len = cfg->seq_points->len;
+ for (i = 0; i < cfg->seq_points->len; ++i) {
+ SeqPoint *sp = &info->seq_points [i];
+ MonoInst *ins = g_ptr_array_index (cfg->seq_points, i);
+
+ sp->il_offset = ins->inst_imm;
+ sp->native_offset = ins->inst_offset;
+
+ /* Used below */
+ ins->backend.size = i;
+ }
+
+ /*
+ * For each sequence point, compute the list of sequence points immediately
+ * following it, this is needed to implement 'step over' in the debugger agent.
+ */
+ next = g_new0 (GSList*, cfg->seq_points->len);
+ for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+ bb_seq_points = g_slist_reverse (bb->seq_points);
+ last = NULL;
+ for (l = bb_seq_points; l; l = l->next) {
+ MonoInst *ins = l->data;
+
+ if (!(ins->flags & MONO_INST_SINGLE_STEP_LOC))
+ continue;
+
+ if (last != NULL) {
+ /* Link with the previous seq point in the same bb */
+ next [last->backend.size] = g_slist_append (next [last->backend.size], GUINT_TO_POINTER (ins->backend.size));
+ } else {
+ /* Link with the last bb in the previous bblocks */
+ /*
+ * FIXME: What if the prev bb doesn't have a seq point, but
+ * one of its predecessors has ?
+ */
+ for (i = 0; i < bb->in_count; ++i) {
+ in_bb = bb->in_bb [i];
+
+ if (in_bb->last_seq_point)
+ next [in_bb->last_seq_point->backend.size] = g_slist_append (next [in_bb->last_seq_point->backend.size], GUINT_TO_POINTER (ins->backend.size));
+ }
+ }
+
+ last = ins;
+ }
+ }
+
+ for (i = 0; i < cfg->seq_points->len; ++i) {
+ SeqPoint *sp = &info->seq_points [i];
+ GSList *l;
+ int j;
+
+ sp->next_len = g_slist_length (next [i]);
+ sp->next = g_new (int, sp->next_len);
+ j = 0;
+ for (l = next [i]; l; l = l->next)
+ sp->next [j ++] = GPOINTER_TO_UINT (l->data);
+ g_slist_free (next [i]);
+ }
+ g_free (next);
+
+ cfg->seq_point_info = info;
+
+ // FIXME: dynamic methods
+ mono_domain_lock (domain);
+ g_hash_table_insert (domain_jit_info (domain)->seq_points, cfg->method_to_register, info);
+ mono_domain_unlock (domain);
+
+ g_ptr_array_free (cfg->seq_points, TRUE);
+ cfg->seq_points = NULL;
+}
+
void
mono_codegen (MonoCompile *cfg)
{
try_llvm = FALSE;
#endif
- if (compile_aot)
- try_llvm = FALSE;
-
restart_compile:
if (try_generic_shared) {
MonoMethod *declaring_method;
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;
if (try_generic_shared)
cfg->generic_sharing_context = (MonoGenericSharingContext*)&cfg->generic_sharing_context;
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)) {
cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;
return cfg;
}
cfg->method_to_register = method_to_register;
- /* No way to obtain the location info for 'this' */
- if (try_generic_shared) {
- cfg->exception_message = g_strdup ("gshared");
- cfg->disable_llvm = TRUE;
+ if (cfg->compile_llvm) {
+ /* No way to obtain the location info for 'this' */
+ if (try_generic_shared) {
+ cfg->exception_message = g_strdup ("gshared");
+ cfg->disable_llvm = TRUE;
+ }
+
+ if (cfg->method->save_lmf) {
+ cfg->exception_message = g_strdup ("lmf");
+ cfg->disable_llvm = TRUE;
+ }
+
+ /* FIXME: */
+ if (cfg->method->dynamic) {
+ cfg->exception_message = g_strdup ("dynamic.");
+ cfg->disable_llvm = TRUE;
+ }
}
- if (cfg->method->save_lmf) {
- cfg->exception_message = g_strdup ("lmf");
+ header = mono_method_get_header (method_to_compile);
+ if (!header) {
+ MonoLoaderError *error;
+
+ if ((error = mono_loader_get_last_error ())) {
+ cfg->exception_type = error->exception_type;
+ } else {
+ 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 ())
+ MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
+ return cfg;
+ }
+
+ if (header->clauses) {
+ /*
+ * Cannot be enabled until LLVM supports implicit exceptions, or we use
+ * explicit checks, or we disable this for methods which might throw implicit
+ * exceptions inside clauses.
+ */
+ cfg->exception_message = g_strdup ("clauses");
cfg->disable_llvm = TRUE;
}
+#ifdef ENABLE_LLVM
+ {
+ static gboolean inited;
+
+ if (!inited) {
+ mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &methods_with_llvm);
+ mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &methods_without_llvm);
+ inited = TRUE;
+ }
+
+ /*
+ * Check for methods which cannot be compiled by LLVM early, to avoid
+ * the extra compilation pass.
+ */
+ if (COMPILE_LLVM (cfg) && cfg->disable_llvm) {
+ if (cfg->verbose_level >= 1) {
+ //nm = mono_method_full_name (cfg->method, TRUE);
+ printf ("LLVM failed for '%s': %s\n", method->name, cfg->exception_message);
+ //g_free (nm);
+ }
+ InterlockedIncrement (&methods_without_llvm);
+ mono_destroy_compile (cfg);
+ try_llvm = FALSE;
+ goto restart_compile;
+ }
+ }
+#endif
+
/* The debugger has no liveness information, so avoid sharing registers/stack slots */
if (mono_debug_using_mono_debugger () || debug_options.mdb_optimizations) {
cfg->disable_reuse_registers = TRUE;
cfg->opt |= MONO_OPT_ABCREM;
}
- header = mono_method_get_header (method_to_compile);
- if (!header) {
- MonoLoaderError *error;
-
- if ((error = mono_loader_get_last_error ())) {
- cfg->exception_type = error->exception_type;
- } else {
- 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 ())
- MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
- return cfg;
- }
-
if (getenv ("MONO_VERBOSE_METHOD")) {
if (strcmp (cfg->method->name, getenv ("MONO_VERBOSE_METHOD")) == 0)
cfg->verbose_level = 4;
*/
//cfg->enable_extended_bblocks = TRUE;
+ /*We must verify the method before doing any IR generation as mono_compile_create_vars can assert.*/
+ if (mono_compile_is_broken (cfg))
+ return cfg;
+
/*
* create MonoInst* which represents arguments and local variables
*/
cfg->opt &= ~MONO_OPT_BRANCH;
}
+ /* todo: remove code when we have verified that the liveness for try/catch blocks
+ * works perfectly
+ */
+ /*
+ * Currently, this can't be commented out since exception blocks are not
+ * processed during liveness analysis.
+ * It is also needed, because otherwise the local optimization passes would
+ * delete assignments in cases like this:
+ * r1 <- 1
+ * <something which throws>
+ * r1 <- 2
+ * This also allows SSA to be run on methods containing exception clauses, since
+ * SSA will ignore variables marked VOLATILE.
+ */
+ mono_liveness_handle_exception_clauses (cfg);
+
/*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
if (!COMPILE_LLVM (cfg))
/* Depth-first ordering on basic blocks */
cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (cfg->num_bblocks + 1));
+ cfg->max_block_num = cfg->num_bblocks;
+
dfn = 0;
df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
if (cfg->num_bblocks != dfn + 1) {
if (cfg->verbose_level > 1)
g_print ("found unreachable code in BB%d\n", bb->block_num);
bb->code = bb->last_ins = NULL;
+ while (bb->out_count)
+ mono_unlink_bblock (cfg, bb, bb->out_bb [0]);
}
}
for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
return cfg;
}
+ /*
+ if (header->num_clauses)
+ cfg->disable_ssa = TRUE;
+ */
+
//#define DEBUGSSA "logic_run"
#define DEBUGSSA_CLASS "Tests"
#ifdef DEBUGSSA
- if (!header->num_clauses && !cfg->disable_ssa) {
+ if (!cfg->disable_ssa) {
mono_local_cprop (cfg);
#ifndef DISABLE_SSA
}
#else
if (cfg->opt & MONO_OPT_SSA) {
- if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
+ if (!(cfg->comp_done & MONO_COMP_SSA) && !cfg->disable_ssa) {
#ifndef DISABLE_SSA
mono_ssa_compute (cfg);
#endif
}
#ifdef MONO_ARCH_SOFT_FLOAT
- mono_decompose_soft_float (cfg);
+ if (!COMPILE_LLVM (cfg))
+ mono_decompose_soft_float (cfg);
#endif
if (!COMPILE_LLVM (cfg))
mono_decompose_vtype_opts (cfg);
g_list_free (regs);
}
- /* todo: remove code when we have verified that the liveness for try/catch blocks
- * works perfectly
- */
- /*
- * Currently, this can't be commented out since exception blocks are not
- * processed during liveness analysis.
+ /*
+ * Have to call this again to process variables added since the first call.
*/
mono_liveness_handle_exception_clauses (cfg);
//print_dfn (cfg);
/* variables are allocated after decompose, since decompose could create temps */
- if (!cfg->globalra && !COMPILE_LLVM (cfg))
+ if (!cfg->globalra && !COMPILE_LLVM (cfg)) {
mono_arch_allocate_vars (cfg);
+ if (cfg->exception_type)
+ return cfg;
+ }
{
MonoBasicBlock *bb;
if (COMPILE_LLVM (cfg)) {
#ifdef ENABLE_LLVM
char *nm;
- static gboolean inited;
-
- if (!inited) {
- mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &methods_with_llvm);
- mono_counters_register ("Methods JITted without using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &methods_without_llvm);
- inited = TRUE;
- }
/* The IR has to be in SSA form for LLVM */
if (!(cfg->comp_done & MONO_COMP_SSA)) {
cfg->disable_llvm = TRUE;
}
- /* FIXME: */
- if (cfg->method->dynamic) {
- cfg->exception_message = g_strdup ("dynamic.");
- cfg->disable_llvm = TRUE;
- }
-
if (cfg->flags & MONO_CFG_HAS_ARRAY_ACCESS)
mono_decompose_array_access_opts (cfg);
if (!cfg->disable_llvm)
mono_llvm_emit_method (cfg);
+ if (!cfg->disable_llvm && header->num_clauses && !cfg->compile_aot && cfg->llvm_ex_info_len != header->num_clauses) {
+ cfg->exception_message = g_strdup ("clause num mismatch.");
+ cfg->disable_llvm = TRUE;
+ }
if (cfg->disable_llvm) {
- if (cfg->verbose_level >= 2) {
+ if (cfg->verbose_level >= 1) {
//nm = mono_method_full_name (cfg->method, TRUE);
printf ("LLVM failed for '%s': %s\n", method->name, cfg->exception_message);
//g_free (nm);
InterlockedIncrement (&methods_with_llvm);
- if (cfg->verbose_level > 0) {
+ if (cfg->verbose_level > 0 && !cfg->compile_aot) {
nm = mono_method_full_name (cfg->method, TRUE);
g_print ("LLVM Method %s emitted at %p to %p (code length %d) [%s]\n",
nm,
ei->data.catch_class = ec->data.catch_class;
}
- tblock = cfg->cil_offset_to_bb [ec->try_offset];
- g_assert (tblock);
- ei->try_start = cfg->native_code + tblock->native_offset;
- g_assert (tblock->native_offset);
- tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
- g_assert (tblock);
- ei->try_end = cfg->native_code + tblock->native_offset;
- g_assert (tblock->native_offset);
- tblock = cfg->cil_offset_to_bb [ec->handler_offset];
- g_assert (tblock);
- ei->handler_start = cfg->native_code + tblock->native_offset;
+ if (COMPILE_LLVM (cfg)) {
+ if (!cfg->compile_aot) {
+ g_assert (cfg->llvm_ex_info && i < cfg->llvm_ex_info_len);
+ ei->try_start = cfg->llvm_ex_info [i].try_start;
+ ei->try_end = cfg->llvm_ex_info [i].try_end;
+ ei->handler_start = cfg->llvm_ex_info [i].handler_start;
+ }
+ } else {
+ tblock = cfg->cil_offset_to_bb [ec->try_offset];
+ g_assert (tblock);
+ ei->try_start = cfg->native_code + tblock->native_offset;
+ g_assert (tblock->native_offset);
+ tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
+ g_assert (tblock);
+ ei->try_end = cfg->native_code + tblock->native_offset;
+ g_assert (tblock->native_offset);
+ tblock = cfg->cil_offset_to_bb [ec->handler_offset];
+ g_assert (tblock);
+ ei->handler_start = cfg->native_code + tblock->native_offset;
+ }
}
}
mini_gc_create_gc_map (cfg);
- if (cfg->seq_points) {
- // FIXME: dynamic methods
- mono_domain_lock (domain);
- g_hash_table_insert (domain_jit_info (domain)->seq_points, method_to_register, cfg->seq_points);
- mono_domain_unlock (domain);
- }
+ mono_save_seq_point_info (cfg);
if (!cfg->compile_aot) {
mono_domain_lock (cfg->domain);
if (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL)
piinfo->addr = mono_lookup_internal_call (method);
else if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
-#ifdef PLATFORM_WIN32
+#ifdef HOST_WIN32
g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono in modules loaded from byte arrays. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
#else
g_warning ("Method '%s' in assembly '%s' contains native code that cannot be executed by Mono on this platform. The assembly was probably created using C++/CLI.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
mono_domain_unlock (domain);
if (!info) {
- mono_class_setup_vtable (method->klass);
- if (method->klass->exception_type != MONO_EXCEPTION_NONE) {
- if (exc)
- *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
- else
- mono_raise_exception (mono_class_get_exception_for_failure (method->klass));
- return NULL;
+ if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
+ /*
+ * This might be redundant since mono_class_vtable () already does this,
+ * but keep it just in case for moonlight.
+ */
+ mono_class_setup_vtable (method->klass);
+ if (method->klass->exception_type != MONO_EXCEPTION_NONE) {
+ if (exc)
+ *exc = (MonoObject*)mono_class_get_exception_for_failure (method->klass);
+ else
+ mono_raise_exception (mono_class_get_exception_for_failure (method->klass));
+ return NULL;
+ }
}
info = g_new0 (RuntimeInvokeInfo, 1);
invoke = mono_marshal_get_runtime_invoke (method, FALSE);
- info->vtable = mono_class_vtable (domain, method->klass);
+ info->vtable = mono_class_vtable_full (domain, method->klass, TRUE);
g_assert (info->vtable);
if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
{
MonoException *exc = NULL;
MonoJitInfo *ji;
-#if !(defined(MONO_ARCH_USE_SIGACTION) || defined(PLATFORM_WIN32))
+#if !(defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32))
void *info = NULL;
#endif
GET_CONTEXT;
}
#ifdef MONO_ARCH_HAVE_IMT
-static gpointer
+static G_GNUC_UNUSED gpointer
mini_get_imt_trampoline (void)
{
static gpointer tramp = NULL;
debug_options.dyn_runtime_invoke = TRUE;
else if (!strcmp (arg, "gdb"))
debug_options.gdb = TRUE;
+ else if (!strcmp (arg, "explicit-null-checks"))
+ debug_options.explicit_null_checks = TRUE;
+ else if (!strcmp (arg, "gen-seq-points"))
+ debug_options.gen_seq_points = TRUE;
else {
fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
- fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'dyn-runtime-invoke', 'gdb'\n");
+ fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks'\n");
exit (1);
}
}
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->static_rgctx_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
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 (mono_aligned_addr_hash, NULL);
+ info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, g_free);
info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
domain->runtime_info = info;
g_hash_table_destroy (info->jump_trampoline_hash);
g_hash_table_destroy (info->jit_trampoline_hash);
g_hash_table_destroy (info->delegate_trampoline_hash);
- g_hash_table_destroy (info->static_rgctx_trampoline_hash);
+ if (info->static_rgctx_trampoline_hash)
+ g_hash_table_destroy (info->static_rgctx_trampoline_hash);
g_hash_table_destroy (info->llvm_vcall_trampoline_hash);
g_hash_table_destroy (info->runtime_invoke_hash);
+ g_hash_table_destroy (info->seq_points);
+ g_hash_table_destroy (info->arch_seq_points);
if (info->agent_info)
mono_debugger_agent_free_domain_info (domain);
#ifdef JIT_TRAMPOLINES_WORK
mono_install_compile_method (mono_jit_compile_method);
mono_install_free_method (mono_jit_free_method);
-#ifdef ENABLE_LLVM
- /* The runtime currently only uses this for filling out vtables */
- mono_install_trampoline (mono_create_llvm_vcall_trampoline);
+#ifdef MONO_ARCH_LLVM_SUPPORTED
+ if (mono_use_llvm)
+ /* The runtime currently only uses this for filling out vtables */
+ mono_install_trampoline (mono_create_llvm_vcall_trampoline);
+ else
+ mono_install_trampoline (mono_create_jit_trampoline);
#else
mono_install_trampoline (mono_create_jit_trampoline);
#endif
mono_install_imt_thunk_builder (mono_aot_get_imt_thunk);
else
mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
-#ifndef ENABLE_LLVM
- /* LLVM needs a per-method vtable trampoline */
- mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
- /*
- * The imt code in mono_magic_trampoline () can't handle LLVM code. By disabling
- * this, we force iface calls to go through the llvm vcall trampoline.
- */
- mono_install_imt_trampoline (mini_get_imt_trampoline ());
-#endif
+ if (!mono_use_llvm) {
+ /* LLVM needs a per-method vtable trampoline */
+ mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
+ /*
+ * The imt code in mono_magic_trampoline () can't handle LLVM code. By disabling
+ * this, we force iface calls to go through the llvm vcall trampoline.
+ */
+ mono_install_imt_trampoline (mini_get_imt_trampoline ());
+ }
}
#endif
register_icall (mono_create_corlib_exception_2, "mono_create_corlib_exception_2", "object int object object", TRUE);
register_icall (mono_array_new_1, "mono_array_new_1", "object ptr int", FALSE);
register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
+ register_icall (mono_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
#endif
mono_generic_sharing_init ();
mono_get_runtime_build_info (void)
{
if (mono_build_date)
- return g_strdup_printf ("%s %s", FULL_VERSION, mono_build_date);
+ return g_strdup_printf ("%s (%s %s)", VERSION, FULL_VERSION, mono_build_date);
else
- return g_strdup_printf ("%s", FULL_VERSION);
+ return g_strdup_printf ("%s (%s)", VERSION, FULL_VERSION);
}
static void