Merge branch 'master' of github.com:mono/mono into masterwork
[mono.git] / mono / mini / mini.c
index 338bcf8592c8732cba0d74e18f8db0f187539fdf..3b5a7c3196e04ff872b54902d8b2c1c907bb6bb8 100644 (file)
 #include "mini-gc.h"
 #include "debugger-agent.h"
 
-static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex);
+#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
 
-/* 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_generic_class_init_trampoline_llvm = 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 gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex);
 
 #ifdef __native_client_codegen__
 /* Default alignment for Native Client is 32-byte. */
@@ -91,8 +99,8 @@ 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;
@@ -116,11 +124,6 @@ gboolean mono_do_signal_chaining;
 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 for JIT compilation, and whenever
  * it can load AOT code compiled by LLVM.
@@ -502,9 +505,15 @@ mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJ
 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 { \
@@ -1331,7 +1340,7 @@ gboolean
 mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method)
 {
        MonoAssembly *assembly = method->klass->image->assembly;
-       if (method->wrapper_type != MONO_WRAPPER_NONE)
+       if (method->wrapper_type != MONO_WRAPPER_NONE && method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
                return FALSE;
        if (assembly->in_gac || assembly->image == mono_defaults.corlib)
                return FALSE;
@@ -1347,8 +1356,8 @@ mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method)
  * 
  * 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;
@@ -1365,7 +1374,10 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method)
        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;
@@ -1375,19 +1387,23 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method)
                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;
                        }
                }
@@ -1397,11 +1413,10 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method)
        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;
@@ -1411,19 +1426,7 @@ mono_compile_is_broken (MonoCompile *cfg)
                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_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
-       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
@@ -2303,14 +2306,14 @@ mono_destroy_compile (MonoCompile *cfg)
        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
 
@@ -2323,9 +2326,9 @@ mono_get_jit_tls_key (void)
 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;
@@ -2335,9 +2338,9 @@ mono_get_jit_tls_offset (void)
 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;
@@ -2348,15 +2351,15 @@ gint32
 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;
 
@@ -2371,8 +2374,8 @@ mono_get_lmf (void)
 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;
 
@@ -2400,13 +2403,31 @@ mono_get_lmf_addr (void)
 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)
@@ -2418,8 +2439,8 @@ 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
@@ -2464,32 +2485,22 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
 
        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);
-#else
-       lmf->ebp = -1;
-#endif
 
        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
@@ -2500,6 +2511,16 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
        return jit_tls;
 }
 
+static void
+free_jit_tls_data (MonoJitTlsData *jit_tls)
+{
+       mono_arch_free_jit_tls_data (jit_tls);
+       mono_free_altstack (jit_tls);
+
+       g_free (jit_tls->first_lmf);
+       g_free (jit_tls);
+}
+
 static void
 mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
 {
@@ -2509,6 +2530,8 @@ mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
        mono_debugger_thread_created (tid, thread->root_domain_thread, jit_tls, func);
        if (thread)
                thread->jit_data = jit_tls;
+
+       mono_arch_cpu_init ();
 }
 
 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
@@ -2533,22 +2556,17 @@ mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
                thread->jit_data = jit_tls;
        if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
                mono_runtime_setup_stat_profiler ();
+
+       mono_arch_cpu_init ();
 }
 
 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_arch_free_jit_tls_data (jit_tls);
-
-               mono_free_altstack (jit_tls);
-               g_free (jit_tls->first_lmf);
-               g_free (jit_tls);
-               internal->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
@@ -2556,17 +2574,15 @@ mini_thread_cleanup (MonoThread *thread)
                 *
                 * 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);
                }
+
+               free_jit_tls_data (jit_tls);
+
+               thread->jit_data = NULL;
        }
 }
 
@@ -3020,6 +3036,13 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                g_assert_not_reached ();
 #endif
                break;
+       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;
+       }
        default:
                g_assert_not_reached ();
        }
@@ -3489,6 +3512,20 @@ compute_reachable (MonoBasicBlock *bb)
        }
 }
 
+static void
+mono_handle_out_of_line_bblock (MonoCompile *cfg)
+{
+       MonoBasicBlock *bb;
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               if (bb->next_bb && bb->next_bb->out_of_line && bb->last_ins && !MONO_IS_BRANCH_OP (bb->last_ins)) {
+                       MonoInst *ins;
+                       MONO_INST_NEW (cfg, ins, OP_BR);
+                       MONO_ADD_INS (bb, ins);
+                       ins->inst_target_bb = bb->next_bb;
+               }
+       }
+}
+
 static MonoJitInfo*
 create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
 {
@@ -3661,10 +3698,28 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
 
                        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);
+                       ei->try_start = cfg->native_code + tblock->native_offset;
+                       if (tblock->extend_try_block) {
+                               /*
+                                * Extend the try block backwards to include parts of the previous call
+                                * instruction.
+                                * FIXME: This is arch specific.
+                                */
+                               ei->try_start = (guint8*)ei->try_start - 1;
+                       }
                        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];
@@ -3832,7 +3887,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                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
@@ -3930,8 +3985,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                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;
                }
 
@@ -4103,8 +4156,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        //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
@@ -4178,6 +4234,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
         */
        mono_liveness_handle_exception_clauses (cfg);
 
+       mono_handle_out_of_line_bblock (cfg);
+
        /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
 
        if (!COMPILE_LLVM (cfg))
@@ -4539,12 +4597,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                mono_codegen (cfg);
        }
 
-#ifdef ENABLE_LLVM
        if (COMPILE_LLVM (cfg))
-               InterlockedIncrement (&methods_with_llvm);
+               InterlockedIncrement (&mono_jit_stats.methods_with_llvm);
        else
-               InterlockedIncrement (&methods_without_llvm);
-#endif
+               InterlockedIncrement (&mono_jit_stats.methods_without_llvm);
 
        if (cfg->verbose_level >= 2) {
                char *id =  mono_method_full_name (cfg->method, FALSE);
@@ -4562,7 +4618,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
 #endif
 
-       mono_save_xdebug_info (cfg);
+       if (!cfg->compile_aot)
+               mono_save_xdebug_info (cfg);
 
        mini_gc_create_gc_map (cfg);
  
@@ -4697,6 +4754,13 @@ mono_emit_jit_map (MonoJitInfo *jinfo)
                g_free (name);
        }
 }
+
+gboolean
+mono_jit_map_is_enabled (void)
+{
+       return perf_map_file != NULL;
+}
+
 #endif
 
 static gpointer
@@ -4708,6 +4772,8 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        MonoVTable *vtable;
        MonoException *ex = NULL;
        guint32 prof_options;
+       GTimer *jit_timer;
+       MonoMethod *prof_method;
 
 #ifdef MONO_USE_AOT_COMPILER
        if (opt & MONO_OPT_AOT) {
@@ -4743,7 +4809,13 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                                mono_lookup_pinvoke_call (method, NULL, NULL);
                }
                nm = mono_marshal_get_native_wrapper (method, check_for_pending_exc, FALSE);
-               return mono_get_addr_from_ftnptr (mono_compile_method (nm));
+               code = mono_get_addr_from_ftnptr (mono_compile_method (nm));
+               jinfo = mono_jit_info_table_find (target_domain, code);
+               if (!jinfo)
+                       jinfo = mono_jit_info_table_find (mono_domain_get (), code);
+               if (jinfo)
+                       mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
+               return code;
 
                //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
                //mono_debug_add_wrapper (method, nm);
@@ -4802,7 +4874,14 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                return NULL;
        }
 
+       jit_timer = g_timer_new ();
+
        cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
+       prof_method = cfg->method;
+
+       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:
@@ -4869,6 +4948,9 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                ex = exp;
                break;
        }
+       case MONO_EXCEPTION_OUT_OF_MEMORY:
+               ex = mono_domain_get ()->out_of_memory_ex;
+               break;
        default:
                g_assert_not_reached ();
        }
@@ -4954,8 +5036,10 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                                /* 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);
                        }
-               } else {
-                       mono_profiler_method_end_jit (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);
                }
        }
 
@@ -5001,11 +5085,16 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
                /* 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);
                }
        }
@@ -5390,7 +5479,11 @@ SIG_HANDLER_SIGNATURE (mono_sigfpe_signal_handler)
 
 #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
@@ -5427,6 +5520,7 @@ SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler)
 {
        MonoJitInfo *ji;
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+       gpointer fault_addr = NULL;
 
        GET_CONTEXT;
 
@@ -5441,6 +5535,7 @@ SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler)
 #endif
 
 #if !defined(HOST_WIN32) && defined(HAVE_SIG_INFO)
+       fault_addr = info->si_addr;
        if (mono_aot_is_pagefault (info->si_addr)) {
                mono_aot_handle_pagefault (info->si_addr);
                return;
@@ -5460,11 +5555,23 @@ SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler)
        if (mono_handle_soft_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr))
                return;
 
+#ifdef MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX
+       /* info->si_addr seems to be NULL on some kernels when handling stack overflows */
+       fault_addr = info->si_addr;
+       if (fault_addr == NULL) {
+               MonoContext mctx;
+
+               mono_arch_sigctx_to_monoctx (ctx, &mctx);
+
+               fault_addr = MONO_CONTEXT_GET_SP (&mctx);
+       }
+#endif
+
        /* The hard-guard page has been hit: there is not much we can do anymore
         * Print a hopefully clear message and abort.
         */
        if (jit_tls->stack_size && 
-                       ABS ((guint8*)info->si_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 32768) {
+               ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
                const char *method;
                /* we don't do much now, but we can warn the user with a useful message */
                fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
@@ -5556,6 +5663,7 @@ mini_get_vtable_trampoline (int slot_index)
 
                        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;
@@ -5669,6 +5777,16 @@ mini_get_addr_from_ftnptr (gpointer descr)
 #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
@@ -5777,6 +5895,14 @@ mini_init (const char *filename, const char *runtime_version)
                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
@@ -5800,6 +5926,9 @@ mini_init (const char *filename, const char *runtime_version)
 #endif
 
        mono_install_callbacks (&callbacks);
+
+       if (getenv ("MONO_DEBUG") != NULL)
+               mini_parse_debug_options ();
        
        mono_arch_cpu_init ();
 
@@ -5809,9 +5938,6 @@ mini_init (const char *filename, const char *runtime_version)
 
        mini_gc_init ();
 
-       if (getenv ("MONO_DEBUG") != NULL)
-               mini_parse_debug_options ();
-
        if (getenv ("MONO_XDEBUG")) {
                char *xdebug_opts = getenv ("MONO_XDEBUG");
                mono_xdebug_init (xdebug_opts);
@@ -5825,9 +5951,11 @@ mini_init (const char *filename, const char *runtime_version)
        }
 
 #ifdef ENABLE_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) {
+               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 ();
@@ -5927,8 +6055,9 @@ mini_init (const char *filename, const char *runtime_version)
        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
@@ -5946,10 +6075,8 @@ mini_init (const char *filename, const char *runtime_version)
 
        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);
-#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);
@@ -6115,6 +6242,9 @@ mini_init (const char *filename, const char *runtime_version)
 
        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 ();
@@ -6155,10 +6285,7 @@ print_jit_stats (void)
 {
        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);
@@ -6260,6 +6387,8 @@ mini_cleanup (MonoDomain *domain)
        mono_runtime_cleanup (domain);
 #endif
 
+       free_jit_tls_data (TlsGetValue (mono_jit_tls_id));
+
        mono_icall_cleanup ();
 
        mono_runtime_cleanup_handlers ();
@@ -6273,6 +6402,8 @@ mini_cleanup (MonoDomain *domain)
                mono_llvm_cleanup ();
 #endif
 
+       mono_aot_cleanup ();
+
        mono_trampolines_cleanup ();
 
        mono_unwind_cleanup ();
@@ -6282,9 +6413,12 @@ mini_cleanup (MonoDomain *domain)
        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 ();
@@ -6403,4 +6537,10 @@ mono_cfg_add_try_hole (MonoCompile *cfg, MonoExceptionClause *clause, guint8 *st
        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