-/*
- * mini.c: The new Mono code generator.
+/**
+ * \file
+ * The new Mono code generator.
*
* Authors:
* Paolo Molaro (lupus@ximian.com)
#include <mono/metadata/threads.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
-#include "mono/metadata/profiler.h"
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/environment.h>
#include <mono/utils/dtrace.h>
#include <mono/utils/mono-threads.h>
#include <mono/utils/mono-threads-coop.h>
-#include <mono/io-layer/io-layer.h>
#include "mini.h"
#include "seq-points.h"
#include "debugger-agent.h"
#include "llvm-runtime.h"
#include "mini-llvm.h"
+#include "lldb.h"
MonoTraceSpec *mono_jit_trace_calls;
MonoMethodDesc *mono_inject_async_exc_method;
}
}
-#define MONO_INIT_VARINFO(vi,id) do { \
- (vi)->range.first_use.pos.bid = 0xffff; \
- (vi)->reg = -1; \
- (vi)->idx = (id); \
-} while (0)
-
/**
* mono_unlink_bblock:
*
cfg->varinfo [num] = inst;
- MONO_INIT_VARINFO (&cfg->vars [num], num);
- MONO_VARINFO (cfg, num)->vreg = vreg;
+ cfg->vars [num].idx = num;
+ cfg->vars [num].vreg = vreg;
+ cfg->vars [num].range.first_use.pos.bid = 0xffff;
+ cfg->vars [num].reg = -1;
if (vreg != -1)
set_vreg_to_inst (cfg, vreg, inst);
g_free (cfg);
}
-static MonoInst*
-mono_create_tls_get_offset (MonoCompile *cfg, int offset)
-{
- MonoInst* ins;
-
- if (!cfg->backend->have_tls_get)
- return NULL;
-
- if (offset == -1)
- return NULL;
-
- MONO_INST_NEW (cfg, ins, OP_TLS_GET);
- ins->dreg = mono_alloc_preg (cfg);
- ins->inst_offset = offset;
- return ins;
-}
-
-gboolean
-mini_tls_get_supported (MonoCompile *cfg, MonoTlsKey key)
-{
- if (!cfg->backend->have_tls_get)
- return FALSE;
-
- if (cfg->compile_aot)
- return cfg->backend->have_tls_get_reg;
- else
- return mini_get_tls_offset (key) != -1;
-}
-
-MonoInst*
-mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
-{
- if (!cfg->backend->have_tls_get)
- return NULL;
-
-#ifdef HAVE_KW_THREAD
- /*
- * MONO_THREAD_VAR_OFFSET definitions don't work when loading mono as a
- * dynamic library. This means that we need to be conservative and don't
- * aot code that contains these tls chunks.
- *
- * FIXME Remove HAVE_KW_THREAD altogether and use only pthread since it
- * simplifies the code alot.
- */
- if (!cfg->full_aot)
- cfg->disable_aot = TRUE;
-#endif
- /*
- * TLS offsets might be different at AOT time, so load them from a GOT slot and
- * use a different opcode.
- */
- if (cfg->compile_aot) {
- if (cfg->backend->have_tls_get_reg) {
- MonoInst *ins, *c;
-
- EMIT_NEW_TLS_OFFSETCONST (cfg, c, key);
- MONO_INST_NEW (cfg, ins, OP_TLS_GET_REG);
- ins->dreg = mono_alloc_preg (cfg);
- ins->sreg1 = c->dreg;
- return ins;
- } else {
- return NULL;
- }
- }
-
- return mono_create_tls_get_offset (cfg, mini_get_tls_offset (key));
-}
-
-MonoInst*
-mono_get_jit_tls_intrinsic (MonoCompile *cfg)
-{
- return mono_create_tls_get (cfg, TLS_KEY_JIT_TLS);
-}
-
-MonoInst*
-mono_get_domain_intrinsic (MonoCompile* cfg)
-{
- return mono_create_tls_get (cfg, TLS_KEY_DOMAIN);
-}
-
-MonoInst*
-mono_get_thread_intrinsic (MonoCompile* cfg)
-{
- return mono_create_tls_get (cfg, TLS_KEY_THREAD);
-}
-
-MonoInst*
-mono_get_lmf_intrinsic (MonoCompile* cfg)
-{
- return mono_create_tls_get (cfg, TLS_KEY_LMF);
-}
-
-MonoInst*
-mono_get_lmf_addr_intrinsic (MonoCompile* cfg)
-{
- return mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
-}
-
void
mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
{
if (cfg->verbose_level > 2)
g_print ("creating locals\n");
- for (i = 0; i < header->num_locals; ++i)
+ for (i = 0; i < header->num_locals; ++i) {
+ if (cfg->verbose_level > 2)
+ g_print ("\tlocal [%d]: ", i);
cfg->locals [i] = mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
+ }
if (cfg->verbose_level > 2)
g_print ("locals done\n");
}
case MONO_PATCH_INFO_SWITCH: {
gpointer *table;
-#if defined(__native_client__) && defined(__native_client_codegen__)
- /* This memory will leak. */
- /* TODO: can we free this when */
- /* making the final jump table? */
- table = g_malloc0 (sizeof(gpointer) * patch_info->data.table->table_size);
-#else
if (cfg->method->dynamic) {
table = (void **)mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
} else {
table = (void **)mono_domain_code_reserve (cfg->domain, sizeof (gpointer) * patch_info->data.table->table_size);
}
-#endif
for (i = 0; i < patch_info->data.table->table_size; i++) {
/* Might be NULL if the switch is eliminated */
mono_bb_deduplicate_op_il_seq_points (cfg, bb);
}
- if (cfg->prof_options & MONO_PROFILE_COVERAGE)
- cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
-
code = mono_arch_emit_prolog (cfg);
cfg->code_len = code - cfg->native_code;
mono_arch_emit_epilog (cfg);
cfg->epilog_end = cfg->code_len;
}
+
+ if (bb->clause_hole)
+ mono_cfg_add_try_hole (cfg, bb->clause_hole, cfg->native_code + bb->native_offset, bb);
}
mono_arch_emit_exceptions (cfg);
/* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
- unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
+ unwindlen = mono_arch_unwindinfo_init_method_unwind_info (cfg);
#endif
if (cfg->method->dynamic) {
} else {
mono_domain_code_commit (code_domain, cfg->native_code, cfg->code_size, cfg->code_len);
}
-#if defined(__native_client_codegen__) && defined(__native_client__)
- cfg->native_code = code_dest;
-#endif
- mono_profiler_code_buffer_new (cfg->native_code, cfg->code_len, MONO_PROFILER_CODE_BUFFER_METHOD, cfg->method);
+ MONO_PROFILER_RAISE (jit_code_buffer, (cfg->native_code, cfg->code_len, MONO_PROFILER_CODE_BUFFER_METHOD, cfg->method));
mono_arch_flush_icache (cfg->native_code, cfg->code_len);
mono_debug_close_method (cfg);
#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
- mono_arch_unwindinfo_install_unwind_info (&cfg->arch.unwindinfo, cfg->native_code, cfg->code_len);
+ mono_arch_unwindinfo_install_method_unwind_info (&cfg->arch.unwindinfo, cfg->native_code, cfg->code_len);
#endif
}
MonoExceptionClause *ec = &header->clauses [i];
MonoJitExceptionInfo *ei = &jinfo->clauses [i];
MonoBasicBlock *tblock;
- MonoInst *exvar, *spvar;
+ MonoInst *exvar;
ei->flags = ec->flags;
if (G_UNLIKELY (cfg->verbose_level >= 4))
printf ("IL clause: try 0x%x-0x%x handler 0x%x-0x%x filter 0x%x\n", ec->try_offset, ec->try_offset + ec->try_len, ec->handler_offset, ec->handler_offset + ec->handler_len, ec->flags == MONO_EXCEPTION_CLAUSE_FILTER ? ec->data.filter_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;
- }
+ 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];
if (cfg->verbose_level > 1)
printf ("ADDING SAFE POINT TO BB %d\n", bblock->block_num);
-#if defined(__native_client_codegen__)
- NEW_AOTCONST (cfg, poll_addr, MONO_PATCH_INFO_GC_SAFE_POINT_FLAG, (gpointer)&__nacl_thread_suspension_needed);
-#else
g_assert (mono_threads_is_coop_enabled ());
NEW_AOTCONST (cfg, poll_addr, MONO_PATCH_INFO_GC_SAFE_POINT_FLAG, (gpointer)&mono_polling_required);
-#endif
MONO_INST_NEW (cfg, ins, OP_GC_SAFE_POINT);
ins->sreg1 = poll_addr->dreg;
{
MonoBasicBlock *bb;
-#if !defined(__native_client_codegen__)
if (!mono_threads_is_coop_enabled ())
return;
-#endif
if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
-#if defined(__native_client__) || defined(__native_client_codegen__)
- gpointer poll_func = &mono_nacl_gc;
-#else
g_assert (mono_threads_is_coop_enabled ());
gpointer poll_func = &mono_threads_state_poll;
-#endif
if (info && info->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER && info->d.icall.func == poll_func) {
if (cfg->verbose_level > 1)
#endif
#ifdef MONO_ARCH_GSHARED_SUPPORTED
backend->gshared_supported = 1;
-#endif
- if (MONO_ARCH_HAVE_TLS_GET)
- backend->have_tls_get = 1;
-#ifdef MONO_ARCH_HAVE_TLS_GET_REG
- backend->have_tls_get_reg = 1;
#endif
if (MONO_ARCH_USE_FPSTACK)
backend->use_fpstack = 1;
gboolean llvm = (flags & JIT_FLAG_LLVM) ? 1 : 0;
#endif
static gboolean verbose_method_inited;
- static const char *verbose_method_name;
+ static char *verbose_method_name;
InterlockedIncrement (&mono_jit_stats.methods_compiled);
- if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
- mono_profiler_method_jit (method);
+ MONO_PROFILER_RAISE (jit_begin, (method));
if (MONO_METHOD_COMPILE_BEGIN_ENABLED ())
MONO_PROBE_METHOD_COMPILE_BEGIN (method);
if (opts & MONO_OPT_GSHARED) {
if (try_generic_shared)
- mono_stats.generics_sharable_methods++;
+ InterlockedIncrement (&mono_stats.generics_sharable_methods);
else if (mono_method_is_generic_impl (method))
- mono_stats.generics_unsharable_methods++;
+ InterlockedIncrement (&mono_stats.generics_unsharable_methods);
}
#ifdef ENABLE_LLVM
cfg->method = method_to_compile;
cfg->mempool = mono_mempool_new ();
cfg->opt = opts;
- cfg->prof_options = mono_profiler_get_events ();
cfg->run_cctors = run_cctors;
cfg->domain = domain;
cfg->verbose_level = mini_verbose;
cfg->llvm_only = (flags & JIT_FLAG_LLVM_ONLY) != 0;
cfg->backend = current_backend;
-#ifdef PLATFORM_ANDROID
+#ifdef HOST_ANDROID
if (cfg->method->wrapper_type != MONO_WRAPPER_NONE) {
/* FIXME: Why is this needed */
cfg->gen_seq_points = FALSE;
cfg->gen_seq_points = FALSE;
cfg->gen_sdb_seq_points = FALSE;
}
- /* coop / nacl requires loop detection to happen */
-#if defined(__native_client_codegen__)
- cfg->opt |= MONO_OPT_LOOP;
-#else
+ /* coop requires loop detection to happen */
if (mono_threads_is_coop_enabled ())
cfg->opt |= MONO_OPT_LOOP;
-#endif
cfg->explicit_null_checks = debug_options.explicit_null_checks || (flags & JIT_FLAG_EXPLICIT_NULL_CHECKS);
cfg->soft_breakpoints = debug_options.soft_breakpoints;
cfg->check_pinvoke_callconv = debug_options.check_pinvoke_callconv;
if (cfg->gen_seq_points)
cfg->seq_points = g_ptr_array_new ();
- mono_error_init (&cfg->error);
+ error_init (&cfg->error);
if (cfg->compile_aot && !try_generic_shared && (method->is_generic || mono_class_is_gtd (method->klass) || method_is_gshared)) {
cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;
}
cfg->method_to_register = method_to_register;
- mono_error_init (&err);
+ error_init (&err);
sig = mono_method_signature_checked (cfg->method, &err);
if (!sig) {
cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
}
#endif
+ cfg->prof_flags = mono_profiler_get_call_instrumentation_flags (cfg->method);
+
/* The debugger has no liveness information, so avoid sharing registers/stack slots */
- if (debug_options.mdb_optimizations) {
+ if (debug_options.mdb_optimizations || MONO_CFG_PROFILE_CALL_CONTEXT (cfg)) {
cfg->disable_reuse_registers = TRUE;
cfg->disable_reuse_stack_slots = TRUE;
/*
cfg->disable_ssa = TRUE;
}
+ if (cfg->num_varinfo > 10000 && !cfg->llvm_only)
+ /* Disable llvm for overly complex methods */
+ cfg->disable_ssa = TRUE;
+
if (cfg->opt & MONO_OPT_LOOP) {
MONO_TIME_TRACK (mono_jit_stats.jit_compile_dominator_info, mono_compile_dominator_info (cfg, MONO_COMP_DOM | MONO_COMP_IDOM));
MONO_TIME_TRACK (mono_jit_stats.jit_compute_natural_loops, mono_compute_natural_loops (cfg));
}
#endif
- if (!cfg->compile_aot)
- mono_save_xdebug_info (cfg);
-
MONO_TIME_TRACK (mono_jit_stats.jit_gc_create_gc_map, mini_gc_create_gc_map (cfg));
-
MONO_TIME_TRACK (mono_jit_stats.jit_save_seq_point_info, mono_save_seq_point_info (cfg));
+ if (!cfg->compile_aot) {
+ mono_save_xdebug_info (cfg);
+ mono_lldb_save_method_info (cfg);
+ }
+
if (cfg->verbose_level >= 2) {
char *id = mono_method_full_name (cfg->method, FALSE);
mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
g_free (id);
}
- if (!cfg->compile_aot) {
+ if (!cfg->compile_aot && !(flags & JIT_FLAG_DISCARD_RESULTS)) {
mono_domain_lock (cfg->domain);
mono_jit_info_table_add (cfg->domain, cfg->jit_info);
MonoJitInfo *jinfo, *info;
MonoVTable *vtable;
MonoException *ex = NULL;
- guint32 prof_options;
GTimer *jit_timer;
MonoMethod *prof_method, *shared;
- mono_error_init (error);
+ error_init (error);
if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
if (!jinfo)
jinfo = mono_jit_info_table_find (mono_domain_get (), (char *)code);
if (jinfo)
- mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
+ MONO_PROFILER_RAISE (jit_done, (method, jinfo));
return code;
} else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
const char *name = method->name;
}
if (ex) {
- if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
- mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
+ MONO_PROFILER_RAISE (jit_failed, (method));
mono_destroy_compile (cfg);
mono_error_set_exception_instance (error, ex);
code = cfg->native_code;
if (cfg->gshared && mono_method_is_generic_sharable (method, FALSE))
- mono_stats.generics_shared_methods++;
+ InterlockedIncrement (&mono_stats.generics_shared_methods);
if (cfg->gsharedvt)
- mono_stats.gsharedvt_methods++;
+ InterlockedIncrement (&mono_stats.gsharedvt_methods);
}
jinfo = cfg->jit_info;
- prof_options = cfg->prof_options;
-
/*
* Update global stats while holding a lock, instead of doing many
* InterlockedIncrement operations during JITting.
return NULL;
}
- if (prof_options & MONO_PROFILE_JIT_COMPILATION) {
- if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
- if (mono_marshal_method_from_wrapper (method)) {
- /* Native func wrappers have no method */
- /* The profiler doesn't know about wrappers, so pass the original icall method */
- mono_profiler_method_end_jit (mono_marshal_method_from_wrapper (method), jinfo, MONO_PROFILE_OK);
- }
- }
- mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
- if (prof_method != method) {
- mono_profiler_method_end_jit (prof_method, jinfo, MONO_PROFILE_OK);
+ if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
+ if (mono_marshal_method_from_wrapper (method)) {
+ /* Native func wrappers have no method */
+ /* The profiler doesn't know about wrappers, so pass the original icall method */
+ MONO_PROFILER_RAISE (jit_done, (mono_marshal_method_from_wrapper (method), jinfo));
}
}
+ MONO_PROFILER_RAISE (jit_done, (method, jinfo));
+ if (prof_method != method)
+ MONO_PROFILER_RAISE (jit_done, (prof_method, jinfo));
- if (!mono_runtime_class_init_full (vtable, error))
- return NULL;
+ if (!(method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE ||
+ method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
+ method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE)) {
+ if (!mono_runtime_class_init_full (vtable, error))
+ return NULL;
+ }
return code;
}
* mini_get_underlying_type:
*
* Return the type the JIT will use during compilation.
- * Handles: byref, enums, native types, generic sharing.
+ * Handles: byref, enums, native types, bool/char, ref types, generic sharing.
* For gsharedvt types, it will return the original VAR/MVAR.
*/
MonoType*