/*
* mini.c: The new Mono code generator.
*
- * Author:
+ * Authors:
* Paolo Molaro (lupus@ximian.com)
* Dietmar Maurer (dietmar@ximian.com)
*
- * (C) 2002 Ximian, Inc.
+ * Copyright 2002-2003 Ximian, Inc.
+ * Coprygith 2003-2010 Novell, Inc.
*/
+#define MONO_LLVM_IN_MINI 1
#include <config.h>
#include <signal.h>
#ifdef HAVE_ALLOCA_H
#include <mono/metadata/verify-internals.h>
#include <mono/metadata/mempool-internals.h>
#include <mono/metadata/attach.h>
+#include <mono/metadata/runtime.h>
#include <mono/utils/mono-math.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/dtrace.h>
#include "mini.h"
+#include "mini-llvm.h"
#include "tasklets.h"
#include <string.h>
#include <ctype.h>
#include "mini-gc.h"
#include "debugger-agent.h"
+#if defined(HAVE_KW_THREAD)
+#define MINI_FAST_TLS_SET(x,y) x = y
+#define MINI_FAST_TLS_GET(x) x
+#define MINI_FAST_TLS_INIT(x)
+#define MINI_FAST_TLS_DECLARE(x) static __thread gpointer x MONO_TLS_FAST;
+#define MINI_HAVE_FAST_TLS
+#define MINI_THREAD_VAR_OFFSET(x,y) MONO_THREAD_VAR_OFFSET(x,y)
+#elif (defined(__APPLE__) && defined(__i386__))
+#define MINI_FAST_TLS_SET(x,y) pthread_setspecific(x, y)
+#define MINI_FAST_TLS_GET(x) pthread_getspecific(x)
+#define MINI_FAST_TLS_INIT(x) pthread_key_create(&x, NULL)
+#define MINI_FAST_TLS_DECLARE(x) static pthread_key_t x;
+#define MINI_HAVE_FAST_TLS
+#define MINI_THREAD_VAR_OFFSET(x,y) y = (gint32) x
+#else
+#define MINI_THREAD_VAR_OFFSET(x,y) MONO_THREAD_VAR_OFFSET(x,y)
+#endif
+
static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex);
-/* helper methods signature */
-/* FIXME: Make these static again */
-MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
-MonoMethodSignature *helper_sig_domain_get = NULL;
-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;
+#ifdef __native_client_codegen__
+/* Default alignment for Native Client is 32-byte. */
+guint8 nacl_align_byte = 0xe0;
+#endif
static guint32 default_opt = 0;
static gboolean default_opt_set = FALSE;
guint32 mono_jit_tls_id = -1;
-#ifdef HAVE_KW_THREAD
-static __thread gpointer mono_jit_tls MONO_TLS_FAST;
+#ifdef MINI_HAVE_FAST_TLS
+MINI_FAST_TLS_DECLARE(mono_jit_tls);
#endif
MonoTraceSpec *mono_jit_trace_calls = NULL;
static gboolean mono_using_xdebug;
static int mini_verbose = 0;
-/* Statistics */
-#ifdef ENABLE_LLVM
-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.
- * 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.
+ * This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
+ * it can load AOT code compiled by LLVM.
*/
-#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)
gboolean mono_dont_free_global_codeman;
+#ifdef __native_client_codegen__
+
+/* Prevent instructions from straddling a 32-byte alignment boundary. */
+/* Instructions longer than 32 bytes must be aligned internally. */
+/* IN: pcode, instlen */
+/* OUT: pcode */
+void mono_nacl_align_inst(guint8 **pcode, int instlen) {
+ int space_in_block;
+
+ space_in_block = kNaClAlignment - ((uintptr_t)(*pcode) & kNaClAlignmentMask);
+
+ if (G_UNLIKELY (instlen >= kNaClAlignment)) {
+ g_assert_not_reached();
+ } else if (instlen > space_in_block) {
+ *pcode = mono_arch_nacl_pad(*pcode, space_in_block);
+ }
+}
+
+/* Move emitted call sequence to the end of a kNaClAlignment-byte block. */
+/* IN: start pointer to start of call sequence */
+/* IN: pcode pointer to end of call sequence (current "IP") */
+/* OUT: start pointer to the start of the call sequence after padding */
+/* OUT: pcode pointer to the end of the call sequence after padding */
+void mono_nacl_align_call(guint8 **start, guint8 **pcode) {
+ const size_t MAX_NACL_CALL_LENGTH = kNaClAlignment;
+ guint8 copy_of_call[MAX_NACL_CALL_LENGTH];
+ guint8 *temp;
+
+ const size_t length = (size_t)((*pcode)-(*start));
+ g_assert(length < MAX_NACL_CALL_LENGTH);
+
+ memcpy(copy_of_call, *start, length);
+ temp = mono_nacl_pad_call(*start, (guint8)length);
+ memcpy(temp, copy_of_call, length);
+ (*start) = temp;
+ (*pcode) = temp + length;
+}
+
+/* mono_nacl_pad_call(): Insert padding for Native Client call instructions */
+/* code pointer to buffer for emitting code */
+/* ilength length of call instruction */
+guint8 *mono_nacl_pad_call(guint8 *code, guint8 ilength) {
+ int freeSpaceInBlock = kNaClAlignment - ((uintptr_t)code & kNaClAlignmentMask);
+ int padding = freeSpaceInBlock - ilength;
+
+ if (padding < 0) {
+ /* There isn't enough space in this block for the instruction. */
+ /* Fill this block and start a new one. */
+ code = mono_arch_nacl_pad(code, freeSpaceInBlock);
+ freeSpaceInBlock = kNaClAlignment;
+ padding = freeSpaceInBlock - ilength;
+ }
+ g_assert(ilength > 0);
+ g_assert(padding >= 0);
+ g_assert(padding < kNaClAlignment);
+ if (0 == padding) return code;
+ return mono_arch_nacl_pad(code, padding);
+}
+
+guint8 *mono_nacl_align(guint8 *code) {
+ int padding = kNaClAlignment - ((uintptr_t)code & kNaClAlignmentMask);
+ if (padding != kNaClAlignment) code = mono_arch_nacl_pad(code, padding);
+ return code;
+}
+
+void mono_nacl_fix_patches(const guint8 *code, MonoJumpInfo *ji)
+{
+ MonoJumpInfo *patch_info;
+ for (patch_info = ji; patch_info; patch_info = patch_info->next) {
+ unsigned char *ip = patch_info->ip.i + code;
+ ip = mono_arch_nacl_skip_nops(ip);
+ patch_info->ip.i = ip - code;
+ }
+}
+#endif /* __native_client_codegen__ */
+
gboolean
mono_running_on_valgrind (void)
{
void
mono_tramp_info_free (MonoTrampInfo *info)
{
+ GSList *l;
+
g_free (info->name);
- // FIXME: ji + unwind_ops
+ // FIXME: ji
+ for (l = info->unwind_ops; l; l = l->next)
+ g_free (l->data);
+ g_slist_free (info->unwind_ops);
+ g_free (info);
}
#define MONO_INIT_VARINFO(vi,id) do { \
*
* Returns true if the method is invalid.
*/
-gboolean
-mini_method_verify (MonoCompile *cfg, MonoMethod *method)
+static gboolean
+mini_method_verify (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile)
{
GSList *tmp, *res;
gboolean is_fulltrust;
res = mono_method_verify_with_current_settings (method, cfg->skip_visibility);
if ((error = mono_loader_get_last_error ())) {
- cfg->exception_type = error->exception_type;
+ if (fail_compile)
+ cfg->exception_type = error->exception_type;
+ else
+ mono_loader_clear_error ();
if (res)
mono_free_verify_list (res);
return TRUE;
for (tmp = res; tmp; tmp = tmp->next) {
MonoVerifyInfoExtended *info = (MonoVerifyInfoExtended *)tmp->data;
if (info->info.status == MONO_VERIFY_ERROR) {
+ if (fail_compile) {
char *method_name = mono_method_full_name (method, TRUE);
- cfg->exception_type = info->exception_type;
- cfg->exception_message = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message);
+ cfg->exception_type = info->exception_type;
+ cfg->exception_message = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message);
+ g_free (method_name);
+ }
mono_free_verify_list (res);
- g_free (method_name);
return TRUE;
}
if (info->info.status == MONO_VERIFY_NOT_VERIFIABLE && (!is_fulltrust || info->exception_type == MONO_EXCEPTION_METHOD_ACCESS || info->exception_type == MONO_EXCEPTION_FIELD_ACCESS)) {
- char *method_name = mono_method_full_name (method, TRUE);
- cfg->exception_type = info->exception_type;
- cfg->exception_message = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message);
+ if (fail_compile) {
+ char *method_name = mono_method_full_name (method, TRUE);
+ cfg->exception_type = info->exception_type;
+ cfg->exception_message = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message);
+ g_free (method_name);
+ }
mono_free_verify_list (res);
- g_free (method_name);
return TRUE;
}
}
return FALSE;
}
-/*Returns true is something went wrong*/
-static gboolean
-mono_compile_is_broken (MonoCompile *cfg)
+/*Returns true if something went wrong*/
+gboolean
+mono_compile_is_broken (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile)
{
- 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;
method_definition = imethod->declaring;
}
- return !dont_verify && mini_method_verify (cfg, method_definition);
-}
-
-static void
-create_helper_signature (void)
-{
- helper_sig_domain_get = mono_create_icall_signature ("ptr");
- helper_sig_class_init_trampoline = mono_create_icall_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");
+ return !dont_verify && mini_method_verify (cfg, method_definition, fail_compile);
}
static gconstpointer
#else
case MONO_TYPE_I8:
#endif
-#ifdef HAVE_SGEN_GC
- slot_info = &scalar_stack_slots [MONO_TYPE_I];
- break;
-#else
+ if (cfg->disable_ref_noref_stack_slot_share) {
+ slot_info = &scalar_stack_slots [MONO_TYPE_I];
+ break;
+ }
/* Fall through */
-#endif
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
#else
case MONO_TYPE_I8:
#endif
-#ifdef HAVE_SGEN_GC
- slot_info = &scalar_stack_slots [MONO_TYPE_I];
- break;
-#else
+ if (cfg->disable_ref_noref_stack_slot_share) {
+ slot_info = &scalar_stack_slots [MONO_TYPE_I];
+ break;
+ }
/* Fall through */
-#endif
case MONO_TYPE_CLASS:
case MONO_TYPE_OBJECT:
g_free (cfg);
}
-#ifdef HAVE_KW_THREAD
-static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
+#ifdef MINI_HAVE_FAST_TLS
+MINI_FAST_TLS_DECLARE(mono_lmf_addr);
#ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
/*
* When this is defined, the current lmf is stored in this tls variable instead of in
* jit_tls->lmf.
*/
-static __thread gpointer mono_lmf MONO_TLS_FAST;
+MINI_FAST_TLS_DECLARE(mono_lmf);
#endif
#endif
gint32
mono_get_jit_tls_offset (void)
{
-#ifdef HAVE_KW_THREAD
+#ifdef MINI_HAVE_FAST_TLS
int offset;
- MONO_THREAD_VAR_OFFSET (mono_jit_tls, offset);
+ MINI_THREAD_VAR_OFFSET (mono_jit_tls, offset);
return offset;
#else
return -1;
gint32
mono_get_lmf_tls_offset (void)
{
-#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+#if defined(MINI_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
int offset;
- MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
+ MINI_THREAD_VAR_OFFSET(mono_lmf,offset);
return offset;
#else
return -1;
mono_get_lmf_addr_tls_offset (void)
{
int offset;
- MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
+ MINI_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
return offset;
}
MonoLMF *
mono_get_lmf (void)
{
-#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
- return mono_lmf;
+#if defined(MINI_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+ return MINI_FAST_TLS_GET (mono_lmf);
#else
MonoJitTlsData *jit_tls;
MonoLMF **
mono_get_lmf_addr (void)
{
-#ifdef HAVE_KW_THREAD
- return mono_lmf_addr;
+#ifdef MINI_HAVE_FAST_TLS
+ return MINI_FAST_TLS_GET (mono_lmf_addr);
#else
MonoJitTlsData *jit_tls;
void
mono_set_lmf (MonoLMF *lmf)
{
-#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
- mono_lmf = lmf;
+#if defined(MINI_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+ MINI_FAST_TLS_SET (mono_lmf, lmf);
#endif
(*mono_get_lmf_addr ()) = lmf;
}
+static void
+mono_set_jit_tls (MonoJitTlsData *jit_tls)
+{
+ TlsSetValue (mono_jit_tls_id, jit_tls);
+
+#ifdef MINI_HAVE_FAST_TLS
+ MINI_FAST_TLS_SET (mono_jit_tls, jit_tls);
+#endif
+}
+
+static void
+mono_set_lmf_addr (gpointer lmf_addr)
+{
+#ifdef MINI_HAVE_FAST_TLS
+ MINI_FAST_TLS_SET (mono_lmf_addr, lmf_addr);
+#endif
+}
+
/* Called by native->managed wrappers */
void
mono_jit_thread_attach (MonoDomain *domain)
*/
domain = mono_get_root_domain ();
-#ifdef HAVE_KW_THREAD
- if (!mono_lmf_addr) {
+#ifdef MINI_HAVE_FAST_TLS
+ if (!MINI_FAST_TLS_GET (mono_lmf_addr)) {
mono_thread_attach (domain);
}
#else
jit_tls = g_new0 (MonoJitTlsData, 1);
- TlsSetValue (mono_jit_tls_id, jit_tls);
-
-#ifdef HAVE_KW_THREAD
- mono_jit_tls = jit_tls;
-#endif
-
jit_tls->abort_func = abort_func;
jit_tls->end_of_stack = stack_start;
+ mono_set_jit_tls (jit_tls);
+
lmf = g_new0 (MonoLMF, 1);
#ifdef MONO_ARCH_INIT_TOP_LMF_ENTRY
MONO_ARCH_INIT_TOP_LMF_ENTRY (lmf);
jit_tls->first_lmf = lmf;
-#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+#if defined(MINI_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
/* jit_tls->lmf is unused */
- mono_lmf = lmf;
- mono_lmf_addr = &mono_lmf;
+ MINI_FAST_TLS_SET (mono_lmf, lmf);
+ mono_set_lmf_addr (&mono_lmf);
#else
-#if defined(HAVE_KW_THREAD)
- mono_lmf_addr = &jit_tls->lmf;
-#endif
+ mono_set_lmf_addr (&jit_tls->lmf);
jit_tls->lmf = lmf;
#endif
}
static void
-mini_thread_cleanup (MonoThread *thread)
+mini_thread_cleanup (MonoInternalThread *thread)
{
- MonoInternalThread *internal = thread->internal_thread;
- MonoJitTlsData *jit_tls = internal->jit_data;
+ MonoJitTlsData *jit_tls = thread->jit_data;
if (jit_tls) {
mono_debugger_thread_cleanup (jit_tls);
mono_free_altstack (jit_tls);
g_free (jit_tls->first_lmf);
g_free (jit_tls);
- internal->jit_data = NULL;
+ thread->jit_data = NULL;
/* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
* It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
*
* The current offender is mono_thread_manage which cleanup threads from the outside.
*/
- if (internal == mono_thread_internal_current ()) {
- TlsSetValue (mono_jit_tls_id, NULL);
-
-#ifdef HAVE_KW_THREAD
- mono_jit_tls = NULL;
- mono_lmf_addr = NULL;
-#if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
- mono_lmf = NULL;
-#endif
-#endif
+ if (thread == mono_thread_internal_current ()) {
+ mono_set_lmf (NULL);
+ mono_set_jit_tls (NULL);
+ mono_set_lmf_addr (NULL);
}
}
}
g_assert_not_reached ();
#endif
break;
+#ifdef HAVE_SGEN_GC
+ case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: {
+ int card_table_shift_bits;
+ gpointer card_table_mask;
+
+ target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
+ break;
+ }
+#endif
default:
g_assert_not_reached ();
}
}
memcpy (code, cfg->native_code, cfg->code_len);
+#ifdef __native_client_codegen__
+ if (cfg->native_code_alloc) {
+ g_free (cfg->native_code_alloc);
+ cfg->native_code_alloc = 0;
+ }
+ else if (cfg->native_code) {
+ g_free (cfg->native_code);
+ }
+#else
g_free (cfg->native_code);
+#endif
cfg->native_code = code;
code = cfg->native_code + cfg->code_len;
mono_arch_save_unwind_info (cfg);
#endif
+#ifdef __native_client_codegen__
+ mono_nacl_fix_patches (cfg->native_code, cfg->patch_info);
+#endif
+
mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
if (cfg->method->dynamic) {
mini_method_get_context (method_to_compile)->method_inst ||
method_to_compile->klass->valuetype) {
inst = cfg->rgctx_var;
- g_assert (inst->opcode == OP_REGOFFSET);
+ if (!COMPILE_LLVM (cfg))
+ g_assert (inst->opcode == OP_REGOFFSET);
} else {
inst = cfg->args [0];
}
- if (inst->opcode == OP_REGVAR) {
+ if (COMPILE_LLVM (cfg)) {
+ g_assert (cfg->llvm_this_reg != -1);
+ gi->this_in_reg = 0;
+ gi->this_reg = cfg->llvm_this_reg;
+ gi->this_offset = cfg->llvm_this_offset;
+ } else if (inst->opcode == OP_REGVAR) {
gi->this_in_reg = 1;
gi->this_reg = inst->dreg;
} else {
g_assert (tblock->native_offset);
tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
g_assert (tblock);
+ if (!tblock->native_offset) {
+ int j, end;
+ for (j = ec->try_offset + ec->try_len, end = ec->try_offset; j >= end; --j) {
+ MonoBasicBlock *bb = cfg->cil_offset_to_bb [j];
+ if (bb && bb->native_offset) {
+ tblock = bb;
+ break;
+ }
+ }
+ }
ei->try_end = cfg->native_code + tblock->native_offset;
g_assert (tblock->native_offset);
tblock = cfg->cil_offset_to_bb [ec->handler_offset];
MonoCompile *cfg;
int dfn, i, code_size_ratio;
gboolean deadce_has_run = FALSE;
- gboolean try_generic_shared, try_llvm;
+ gboolean try_generic_shared, try_llvm = FALSE;
MonoMethod *method_to_compile, *method_to_register;
mono_jit_stats.methods_compiled++;
mono_profiler_method_jit (method);
if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ())
MONO_PROBE_METHOD_COMPILE_BEGIN (method);
-
+
if (compile_aot)
/*
* We might get passed the original generic method definition or
mono_stats.generics_unsharable_methods++;
}
- try_llvm = TRUE;
-
-#ifndef ENABLE_LLVM
- try_llvm = FALSE;
+#ifdef ENABLE_LLVM
+ try_llvm = mono_use_llvm;
#endif
restart_compile:
}
cfg->method_to_register = method_to_register;
- 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;
- }
- }
-
mono_error_init (&err);
sig = mono_method_signature_checked (cfg->method, &err);
if (!sig) {
return cfg;
}
- if (header->clauses) {
- /*
- * FIXME: LLLVM 2.6/SVN no longer seems to generate correct exception info
- * for JITted code.
- */
- 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);
+ if (COMPILE_LLVM (cfg)) {
+ mono_llvm_check_method_supported (cfg);
+ if (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);
+ }
+ mono_destroy_compile (cfg);
+ try_llvm = FALSE;
+ goto restart_compile;
}
- InterlockedIncrement (&methods_without_llvm);
- mono_destroy_compile (cfg);
- try_llvm = FALSE;
- goto restart_compile;
}
}
#endif
cfg->compute_precise_live_ranges = TRUE;
}
- mini_gc_init_gc_map (cfg);
+ mini_gc_init_cfg (cfg);
if (COMPILE_LLVM (cfg)) {
cfg->opt |= MONO_OPT_ABCREM;
//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))
+ if (mono_compile_is_broken (cfg, cfg->method, TRUE)) {
+ if (mini_get_debug_options ()->break_on_unverified)
+ G_BREAKPOINT ();
return cfg;
+ }
/*
* create MonoInst* which represents arguments and local variables
#endif
if (cfg->comp_done & MONO_COMP_SSA && COMPILE_LLVM (cfg)) {
- if ((cfg->flags & (MONO_CFG_HAS_LDELEMA|MONO_CFG_HAS_CHECK_THIS)) && (cfg->opt & MONO_OPT_ABCREM))
+ /* This removes MONO_INST_FAULT flags too so perform it unconditionally */
+ if (cfg->opt & MONO_OPT_ABCREM)
mono_perform_abc_removal (cfg);
}
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;
}
- InterlockedIncrement (&methods_with_llvm);
-
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",
mono_codegen (cfg);
}
+ if (COMPILE_LLVM (cfg))
+ InterlockedIncrement (&mono_jit_stats.methods_with_llvm);
+ else
+ InterlockedIncrement (&mono_jit_stats.methods_without_llvm);
+
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);
}
#endif
- mono_save_xdebug_info (cfg);
+ if (!cfg->compile_aot)
+ mono_save_xdebug_info (cfg);
mini_gc_create_gc_map (cfg);
g_free (name);
}
}
+
+gboolean
+mono_jit_map_is_enabled (void)
+{
+ return perf_map_file != NULL;
+}
+
#endif
static gpointer
MonoVTable *vtable;
MonoException *ex = NULL;
guint32 prof_options;
+ GTimer *jit_timer;
#ifdef MONO_USE_AOT_COMPILER
if (opt & MONO_OPT_AOT) {
//mono_debug_add_wrapper (method, nm);
} else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
const char *name = method->name;
+ char *full_name, *msg;
MonoMethod *nm;
if (method->klass->parent == mono_defaults.multicastdelegate_class) {
return mono_get_addr_from_ftnptr (mono_compile_method (nm));
}
}
+
+ full_name = mono_method_full_name (method, TRUE);
+ msg = g_strdup_printf ("Unrecognizable runtime implemented method '%s'", full_name);
+ *jit_ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", msg);
+ g_free (full_name);
+ g_free (msg);
return NULL;
}
return NULL;
}
+ jit_timer = g_timer_new ();
+
cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
+ g_timer_stop (jit_timer);
+ mono_jit_stats.jit_time += g_timer_elapsed (jit_timer, NULL);
+ g_timer_destroy (jit_timer);
+
switch (cfg->exception_type) {
case MONO_EXCEPTION_NONE:
break;
/* We can't use a domain specific method in another domain */
if (! ((domain != target_domain) && !info->domain_neutral)) {
MonoVTable *vtable;
+ MonoException *tmpEx;
mono_jit_stats.methods_lookups++;
vtable = mono_class_vtable (domain, method->klass);
g_assert (vtable);
- mono_runtime_class_init (vtable);
+ tmpEx = mono_runtime_class_init_full (vtable, ex == NULL);
+ if (tmpEx) {
+ *ex = tmpEx;
+ return NULL;
+ }
return mono_create_ftnptr (target_domain, info->code_start);
}
}
mono_runtime_class_init (info->vtable);
}
+ /* The wrappers expect this to be initialized to NULL */
+ if (exc)
+ *exc = NULL;
+
#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
if (info->dyn_call_info) {
MonoMethodSignature *sig = mono_method_signature (method);
#if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
if (mono_arch_is_int_overflow (ctx, info))
- exc = mono_get_exception_arithmetic ();
+ /*
+ * The spec says this throws ArithmeticException, but MS throws the derived
+ * OverflowException.
+ */
+ exc = mono_get_exception_overflow ();
else
exc = mono_get_exception_divide_by_zero ();
#else
return mono_get_addr_from_ftnptr (addr);
}
-#ifdef MONO_ARCH_HAVE_IMT
-static G_GNUC_UNUSED gpointer
-mini_get_imt_trampoline (void)
-{
- static gpointer tramp = NULL;
- if (!tramp)
- tramp = mono_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
- return tramp;
-}
-#endif
+static gpointer *vtable_trampolines;
+static int vtable_trampolines_size;
gpointer
mini_get_vtable_trampoline (int slot_index)
{
- static gpointer tramp = NULL;
+ int index = slot_index + MONO_IMT_SIZE;
- if (!tramp)
- tramp = mono_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
- return tramp;
+ g_assert (slot_index >= - MONO_IMT_SIZE);
+ if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
+ mono_jit_lock ();
+ if (!vtable_trampolines || index >= vtable_trampolines_size) {
+ int new_size;
+ gpointer new_table;
+
+ new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
+ while (new_size <= index)
+ new_size *= 2;
+ new_table = g_new0 (gpointer, new_size);
+
+ if (vtable_trampolines)
+ memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
+ g_free (vtable_trampolines);
+ mono_memory_barrier ();
+ vtable_trampolines = new_table;
+ vtable_trampolines_size = new_size;
+ }
+ mono_jit_unlock ();
+ }
+
+ if (!vtable_trampolines [index])
+ vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
+ return vtable_trampolines [index];
+}
+
+static gpointer
+mini_get_imt_trampoline (int slot_index)
+{
+ return mini_get_vtable_trampoline (slot_index - MONO_IMT_SIZE);
}
static void
debug_options.handle_sigint = TRUE;
else if (!strcmp (arg, "keep-delegates"))
debug_options.keep_delegates = TRUE;
+ else if (!strcmp (arg, "reverse-pinvoke-exceptions"))
+ debug_options.reverse_pinvoke_exceptions = TRUE;
else if (!strcmp (arg, "collect-pagefault-stats"))
debug_options.collect_pagefault_stats = TRUE;
else if (!strcmp (arg, "break-on-unverified"))
debug_options.gen_seq_points = TRUE;
else if (!strcmp (arg, "init-stacks"))
debug_options.init_stacks = TRUE;
+ else if (!strcmp (arg, "casts"))
+ debug_options.better_cast_details = 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', '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', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'init-stacks'\n");
exit (1);
}
}
#endif
}
+static void
+register_jit_stats (void)
+{
+ mono_counters_register ("Compiled methods", MONO_COUNTER_JIT | MONO_COUNTER_WORD, &mono_jit_stats.methods_compiled);
+ mono_counters_register ("Methods from AOT", MONO_COUNTER_JIT | MONO_COUNTER_WORD, &mono_jit_stats.methods_aot);
+ mono_counters_register ("Methods JITted using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_with_llvm);
+ mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_without_llvm);
+ mono_counters_register ("Total time spent JITting (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_time);
+}
+
static void runtime_invoke_info_free (gpointer value);
static void
MONO_PROBE_VES_INIT_BEGIN ();
-#ifdef __linux__
+#if defined(__linux__) && !defined(__native_client__)
if (access ("/proc/self/maps", F_OK) != 0) {
g_print ("Mono requires /proc to be mounted.\n");
exit (1);
mini_debugger_init ();
#endif
+#ifdef MINI_HAVE_FAST_TLS
+ MINI_FAST_TLS_INIT (mono_jit_tls);
+ MINI_FAST_TLS_INIT (mono_lmf_addr);
+#ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
+ MINI_FAST_TLS_INIT (mono_lmf);
+#endif
+#endif
+
#ifdef MONO_ARCH_HAVE_TLS_GET
mono_runtime_set_has_tls_get (MONO_ARCH_HAVE_TLS_GET);
#else
#ifdef MONO_ARCH_HAVE_IMT
if (mono_use_imt) {
- if (!mono_use_llvm) {
- /* LLVM needs a per-method vtable trampoline */
- callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
- }
+ callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
+ callbacks.get_imt_trampoline = mini_get_imt_trampoline;
}
#endif
}
#ifdef ENABLE_LLVM
- mono_llvm_init ();
+ if (mono_use_llvm) {
+ if (!mono_llvm_load (NULL)) {
+ mono_use_llvm = FALSE;
+ fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
+ }
+ }
+ if (mono_use_llvm)
+ mono_llvm_init ();
#endif
mono_trampolines_init ();
#ifdef JIT_TRAMPOLINES_WORK
mono_install_compile_method (mono_jit_compile_method);
mono_install_free_method (mono_jit_free_method);
-#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_jump_trampoline (mono_create_jump_trampoline);
mono_install_remoting_trampoline (mono_jit_create_remoting_trampoline);
mono_install_delegate_trampoline (mono_create_delegate_trampoline);
mono_install_imt_thunk_builder (mono_aot_get_imt_thunk);
else
mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
- if (!mono_use_llvm) {
- /*
- * 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
mono_add_internal_call ("Mono.Runtime::mono_runtime_install_handlers",
mono_runtime_install_handlers);
+ mono_create_helper_signatures ();
- create_helper_signature ();
+ register_jit_stats ();
#define JIT_CALLS_WORK
#ifdef JIT_CALLS_WORK
register_icall (mono_get_throw_exception (), "mono_arch_throw_exception", "void object", TRUE);
register_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
-#ifdef MONO_ARCH_HAVE_THROW_EXCEPTION_BY_NAME
- register_icall (mono_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE);
-#endif
-#if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception",
"void ptr", TRUE);
-#endif
register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
register_icall (mono_array_new_2, "mono_array_new_2", "object ptr int int", FALSE);
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_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);
+
+ register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
+ register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
+
#endif
mono_generic_sharing_init ();
{
if (mono_jit_stats.enabled) {
g_print ("Mono Jit statistics\n");
- g_print ("Compiled methods: %ld\n", mono_jit_stats.methods_compiled);
- g_print ("Methods from AOT: %ld\n", mono_jit_stats.methods_aot);
g_print ("Methods cache lookup: %ld\n", mono_jit_stats.methods_lookups);
- g_print ("Method trampolines: %ld\n", mono_jit_stats.method_trampolines);
g_print ("Basic blocks: %ld\n", mono_jit_stats.basic_blocks);
g_print ("Max basic blocks: %ld\n", mono_jit_stats.max_basic_blocks);
g_print ("Allocated vars: %ld\n", mono_jit_stats.allocate_var);
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);
-#ifdef HAVE_SGEN_GC
g_print ("Minor GC collections: %ld\n", mono_stats.minor_gc_count);
-#endif
g_print ("Major GC collections: %ld\n", mono_stats.major_gc_count);
-#ifdef HAVE_SGEN_GC
g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
-#endif
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);
#endif
#ifndef MONO_CROSS_COMPILE
+ mono_runtime_shutdown ();
/*
* mono_runtime_cleanup() and mono_domain_finalize () need to
* be called early since they need the execution engine still
mono_debugger_cleanup ();
#ifdef ENABLE_LLVM
- mono_llvm_cleanup ();
+ if (mono_use_llvm)
+ mono_llvm_cleanup ();
#endif
+ mono_aot_cleanup ();
+
mono_trampolines_cleanup ();
mono_unwind_cleanup ();
g_hash_table_destroy (jit_icall_name_hash);
g_free (emul_opcode_map);
g_free (emul_opcode_opcodes);
+ g_free (vtable_trampolines);
mono_arch_cleanup ();
+ mono_generic_sharing_cleanup ();
+
mono_cleanup ();
mono_trace_cleanup ();
cfg->try_block_holes = g_slist_append_mempool (cfg->mempool, cfg->try_block_holes, hole);
}
+void
+mono_cfg_set_exception (MonoCompile *cfg, int type)
+{
+ cfg->exception_type = type;
+}
+
#endif