2010-02-24 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini.c
index 749e482c9882e09f5e308b91261ccfe0060e2503..f977b3a66c49caba9ae20bb4d015f0327c9b0121 100644 (file)
@@ -21,9 +21,7 @@
 #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>
@@ -55,6 +53,7 @@
 #include <mono/utils/dtrace.h>
 
 #include "mini.h"
+#include "tasklets.h"
 #include <string.h>
 #include <ctype.h>
 #include "trace.h"
 #include "jit-icalls.h"
 
 #include "debug-mini.h"
+#include "mini-gc.h"
+#include "debugger-agent.h"
 
-static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
-static gpointer mono_jit_compile_method (MonoMethod *method);
+static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex);
 
 /* helper methods signature */
 /* FIXME: Make these static again */
@@ -74,6 +74,7 @@ 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;
 
 static guint32 default_opt = 0;
 static gboolean default_opt_set = FALSE;
@@ -102,17 +103,37 @@ int mono_break_at_bb_bb_num;
 gboolean mono_do_x86_stack_align = TRUE;
 const char *mono_build_date;
 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 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;
 
 static MonoCodeManager *global_codeman = NULL;
 
-/* FIXME: Make this static again */
-GHashTable *jit_icall_name_hash = NULL;
+static GHashTable *jit_icall_name_hash = NULL;
 
 static MonoDebugOptions debug_options;
 
@@ -139,17 +160,13 @@ gboolean mono_dont_free_global_codeman;
 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 {
@@ -241,9 +258,10 @@ mono_print_method_from_ip (void *ip)
        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;
@@ -260,9 +278,9 @@ mono_print_method_from_ip (void *ip)
                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);
@@ -449,16 +467,63 @@ mono_bblocks_linked (MonoBasicBlock *bb1, MonoBasicBlock *bb2)
        return FALSE;
 }
 
-MonoInst *
-mono_find_spvar_for_region (MonoCompile *cfg, int region)
+static int
+mono_find_block_region_notry (MonoCompile *cfg, int offset)
 {
-       return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
+       MonoMethod *method = cfg->method;
+       MonoMethodHeader *header = mono_method_get_header (method);
+       MonoExceptionClause *clause;
+       int i;
+
+       for (i = 0; i < header->num_clauses; ++i) {
+               clause = &header->clauses [i];
+               if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
+                   (offset < (clause->handler_offset)))
+                       return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
+                          
+               if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
+                       if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
+                               return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
+                       else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
+                               return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
+                       else
+                               return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
+               }
+       }
+
+       return -1;
+}
+
+/*
+ * 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);
+               
+               /*
+                * This can happen if a try clause is nested inside a finally clause.
+                */
+               int clause_index = (region >> 8) - 1;
+               g_assert (clause_index >= 0 && clause_index < header->num_clauses);
+               
+               region = mono_find_block_region_notry (cfg, header->clauses [clause_index].try_offset);
+       }
+
+       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
@@ -583,7 +648,9 @@ mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
        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:
@@ -694,6 +761,18 @@ mono_op_imm_to_op (int opcode)
                return OP_IAND;
 #else
                return OP_LAND;
+#endif
+       case OP_OR_IMM:
+#if SIZEOF_REGISTER == 4
+               return OP_IOR;
+#else
+               return OP_LOR;
+#endif
+       case OP_XOR_IMM:
+#if SIZEOF_REGISTER == 4
+               return OP_IXOR;
+#else
+               return OP_LXOR;
 #endif
        case OP_IAND_IMM:
                return OP_IAND;
@@ -938,7 +1017,6 @@ mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
 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);
@@ -1090,7 +1168,7 @@ mono_get_array_new_va_signature (int arity)
        res->call_convention = MONO_CALL_VARARG;
 #endif
 
-#ifdef PLATFORM_WIN32
+#ifdef TARGET_WIN32
        res->call_convention = MONO_CALL_C;
 #endif
 
@@ -1200,15 +1278,19 @@ 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) {
+                               char *method_name = mono_method_full_name (method, TRUE);
                                cfg->exception_type = info->exception_type;
-                               cfg->exception_message = g_strdup (info->info.message);
+                               cfg->exception_message = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message);
                                mono_free_verify_list (res);
+                               g_free (method_name);
                                return TRUE;
                        }
-                       if (info->info.status == MONO_VERIFY_NOT_VERIFIABLE && !is_fulltrust) {
+                       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 (info->info.message);
+                               cfg->exception_message = g_strdup_printf ("Error verifying %s: %s", method_name, info->info.message);
                                mono_free_verify_list (res);
+                               g_free (method_name);
                                return TRUE;
                        }
                }
@@ -1218,6 +1300,23 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method)
        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)
 {
@@ -1226,6 +1325,7 @@ 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
@@ -1342,6 +1442,7 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s
        StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
        MonoType *t;
        int nvtypes;
+       gboolean reuse_slot;
 
        LSCAN_DEBUG (printf ("Allocate Stack Slots 2 for %s:\n", mono_method_full_name (cfg->method, TRUE)));
 
@@ -1396,8 +1497,15 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s
 
                        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;
                }
 
+               reuse_slot = TRUE;
+               if (cfg->disable_reuse_stack_slots)
+                       reuse_slot = FALSE;
+
                t = mono_type_get_underlying_type (inst->inst_vtype);
                switch (t->type) {
                case MONO_TYPE_GENERICINST:
@@ -1420,12 +1528,10 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s
                                slot_info = &vtype_stack_slots [nvtypes];
                                nvtypes ++;
                        }
+                       if (cfg->disable_reuse_ref_stack_slots)
+                               reuse_slot = FALSE;
                        break;
-               case MONO_TYPE_CLASS:
-               case MONO_TYPE_OBJECT:
-               case MONO_TYPE_ARRAY:
-               case MONO_TYPE_SZARRAY:
-               case MONO_TYPE_STRING:
+
                case MONO_TYPE_PTR:
                case MONO_TYPE_I:
                case MONO_TYPE_U:
@@ -1433,10 +1539,25 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s
                case MONO_TYPE_I4:
 #else
                case MONO_TYPE_I8:
+#endif
+#ifdef HAVE_SGEN_GC
+                       slot_info = &scalar_stack_slots [MONO_TYPE_I];
+                       break;
+#else
+                       /* Fall through */
+#endif
+
+               case MONO_TYPE_CLASS:
+               case MONO_TYPE_OBJECT:
+               case MONO_TYPE_ARRAY:
+               case MONO_TYPE_SZARRAY:
+               case MONO_TYPE_STRING:
                        /* Share non-float stack slots of the same size */
                        slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
+                       if (cfg->disable_reuse_ref_stack_slots)
+                               reuse_slot = FALSE;
                        break;
-#endif
+
                default:
                        slot_info = &scalar_stack_slots [t->type];
                }
@@ -1554,14 +1675,19 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s
 
                LSCAN_DEBUG (printf ("R%d %s -> 0x%x\n", inst->dreg, mono_type_full_name (t), slot));
 
+               if (!reuse_slot)
+                       slot = 0xffffff;
+
                if (slot == 0xffffff) {
                        /*
                         * Allways allocate valuetypes to sizeof (gpointer) to allow more
                         * 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;
@@ -1619,6 +1745,7 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
        StackSlotInfo *scalar_stack_slots, *vtype_stack_slots, *slot_info;
        MonoType *t;
        int nvtypes;
+       gboolean reuse_slot;
 
        if ((cfg->num_varinfo > 0) && MONO_VARINFO (cfg, 0)->interval)
                return mono_allocate_stack_slots_full2 (cfg, backward, stack_size, stack_align);
@@ -1657,8 +1784,15 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
 
                        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;
                }
 
+               reuse_slot = TRUE;
+               if (cfg->disable_reuse_stack_slots)
+                       reuse_slot = FALSE;
+
                t = mono_type_get_underlying_type (inst->inst_vtype);
                if (t->byref) {
                        slot_info = &scalar_stack_slots [MONO_TYPE_I];
@@ -1684,12 +1818,10 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
                                        slot_info = &vtype_stack_slots [nvtypes];
                                        nvtypes ++;
                                }
+                               if (cfg->disable_reuse_ref_stack_slots)
+                                       reuse_slot = FALSE;
                                break;
-                       case MONO_TYPE_CLASS:
-                       case MONO_TYPE_OBJECT:
-                       case MONO_TYPE_ARRAY:
-                       case MONO_TYPE_SZARRAY:
-                       case MONO_TYPE_STRING:
+
                        case MONO_TYPE_PTR:
                        case MONO_TYPE_I:
                        case MONO_TYPE_U:
@@ -1698,9 +1830,24 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
 #else
                        case MONO_TYPE_I8:
 #endif
+#ifdef HAVE_SGEN_GC
+                               slot_info = &scalar_stack_slots [MONO_TYPE_I];
+                               break;
+#else
+                               /* Fall through */
+#endif
+
+                       case MONO_TYPE_CLASS:
+                       case MONO_TYPE_OBJECT:
+                       case MONO_TYPE_ARRAY:
+                       case MONO_TYPE_SZARRAY:
+                       case MONO_TYPE_STRING:
                                /* Share non-float stack slots of the same size */
                                slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
+                               if (cfg->disable_reuse_ref_stack_slots)
+                                       reuse_slot = FALSE;
                                break;
+
                        default:
                                slot_info = &scalar_stack_slots [t->type];
                        }
@@ -1757,7 +1904,7 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
                        */
                }
 
-               if (cfg->disable_reuse_stack_slots)
+               if (!reuse_slot)
                        slot = 0xffffff;
 
                if (slot == 0xffffff) {
@@ -1767,7 +1914,8 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
                         * 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.
@@ -2097,6 +2245,19 @@ mono_get_lmf_addr (void)
 #else
        MonoJitTlsData *jit_tls;
 
+       if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
+               return &jit_tls->lmf;
+
+       /*
+        * When resolving the call to mono_jit_thread_attach full-aot will look
+        * in the plt, which causes a call into the generic trampoline, which in turn
+        * tries to resolve the lmf_addr creating a cyclic dependency.  We cannot
+        * call mono_jit_thread_attach from the native-to-managed wrapper, without
+        * mono_get_lmf_addr, and mono_get_lmf_addr requires the thread to be attached.
+        */
+
+       mono_jit_thread_attach (NULL);
+       
        if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
                return &jit_tls->lmf;
 
@@ -2105,10 +2266,27 @@ mono_get_lmf_addr (void)
 #endif
 }
 
+void
+mono_set_lmf (MonoLMF *lmf)
+{
+#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+       mono_lmf = lmf;
+#endif
+
+       (*mono_get_lmf_addr ()) = lmf;
+}
+
 /* Called by native->managed wrappers */
 void
 mono_jit_thread_attach (MonoDomain *domain)
 {
+       if (!domain)
+               /* 
+                * Happens when called from AOTed code which is only used in the root
+                * domain.
+                */
+               domain = mono_get_root_domain ();
+
 #ifdef HAVE_KW_THREAD
        if (!mono_lmf_addr) {
                mono_thread_attach (domain);
@@ -2194,10 +2372,10 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
 static void
 mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
 {
-       MonoThread *thread;
+       MonoInternalThread *thread;
        void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
-       thread = mono_thread_current ();
-       mono_debugger_thread_created (tid, thread, jit_tls);
+       thread = mono_thread_internal_current ();
+       mono_debugger_thread_created (tid, thread->root_domain_thread, jit_tls, func);
        if (thread)
                thread->jit_data = jit_tls;
 }
@@ -2216,10 +2394,10 @@ mono_thread_abort_dummy (MonoObject *obj)
 static void
 mono_thread_attach_cb (gsize tid, gpointer stack_start)
 {
-       MonoThread *thread;
+       MonoInternalThread *thread;
        void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
-       thread = mono_thread_current ();
-       mono_debugger_thread_created (tid, thread, (MonoJitTlsData *) jit_tls);
+       thread = mono_thread_internal_current ();
+       mono_debugger_thread_created (tid, thread->root_domain_thread, (MonoJitTlsData *) jit_tls, NULL);
        if (thread)
                thread->jit_data = jit_tls;
        if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
@@ -2229,7 +2407,8 @@ mono_thread_attach_cb (gsize tid, gpointer stack_start)
 static void
 mini_thread_cleanup (MonoThread *thread)
 {
-       MonoJitTlsData *jit_tls = thread->jit_data;
+       MonoInternalThread *internal = thread->internal_thread;
+       MonoJitTlsData *jit_tls = internal->jit_data;
 
        if (jit_tls) {
                mono_debugger_thread_cleanup (jit_tls);
@@ -2238,7 +2417,7 @@ mini_thread_cleanup (MonoThread *thread)
                mono_free_altstack (jit_tls);
                g_free (jit_tls->first_lmf);
                g_free (jit_tls);
-               thread->jit_data = NULL;
+               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
@@ -2246,7 +2425,7 @@ mini_thread_cleanup (MonoThread *thread)
                 *
                 * The current offender is mono_thread_manage which cleanup threads from the outside.
                 */
-               if (thread == mono_thread_current ()) {
+               if (internal == mono_thread_internal_current ()) {
                        TlsSetValue (mono_jit_tls_id, NULL);
 
 #ifdef HAVE_KW_THREAD
@@ -2358,6 +2537,8 @@ mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
        case MONO_PATCH_INFO_SWITCH:
                res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
                memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
+               res->data.table->table = mono_mempool_alloc (mp, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
+               memcpy (res->data.table->table, patch_info->data.table->table, sizeof (MonoBasicBlock*) * patch_info->data.table->table_size);
                break;
        case MONO_PATCH_INFO_RGCTX_FETCH:
                res->data.rgctx_entry = mono_mempool_alloc (mp, sizeof (MonoJumpInfoRgctxEntry));
@@ -2383,6 +2564,8 @@ mono_patch_info_hash (gconstpointer data)
        case MONO_PATCH_INFO_LDTOKEN:
        case MONO_PATCH_INFO_DECLSEC:
                return (ji->type << 8) | ji->data.token->token;
+       case MONO_PATCH_INFO_INTERNAL_METHOD:
+               return (ji->type << 8) | g_str_hash (ji->data.name);
        case MONO_PATCH_INFO_VTABLE:
        case MONO_PATCH_INFO_CLASS:
        case MONO_PATCH_INFO_IID:
@@ -2392,10 +2575,10 @@ mono_patch_info_hash (gconstpointer data)
        case MONO_PATCH_INFO_METHOD:
        case MONO_PATCH_INFO_METHOD_JUMP:
        case MONO_PATCH_INFO_IMAGE:
-       case MONO_PATCH_INFO_INTERNAL_METHOD:
        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
        case MONO_PATCH_INFO_FIELD:
        case MONO_PATCH_INFO_SFLDA:
+       case MONO_PATCH_INFO_SEQ_POINT_INFO:
                return (ji->type << 8) | (gssize)ji->data.target;
        default:
                return (ji->type << 8);
@@ -2431,6 +2614,15 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
                        (ji1->data.token->context.method_inst != ji2->data.token->context.method_inst))
                        return 0;
                break;
+       case MONO_PATCH_INFO_INTERNAL_METHOD:
+               return g_str_equal (ji1->data.name, ji2->data.name);
+
+       case MONO_PATCH_INFO_RGCTX_FETCH: {
+               MonoJumpInfoRgctxEntry *e1 = ji1->data.rgctx_entry;
+               MonoJumpInfoRgctxEntry *e2 = ji2->data.rgctx_entry;
+
+               return e1->method == e2->method && e1->in_mrgctx == e2->in_mrgctx && e1->info_type == e2->info_type && mono_patch_info_equal (e1->data, e2->data);
+       }
        default:
                if (ji1->data.target != ji2->data.target)
                        return 0;
@@ -2448,7 +2640,11 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
 
        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:
@@ -2480,12 +2676,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                        target = code;
                } else {
                        /* get the trampoline to the method from the domain */
-                       if (method && method->wrapper_type == MONO_WRAPPER_STATIC_RGCTX_INVOKE) {
-                               target = mono_create_jit_trampoline_in_domain (mono_domain_get (),
-                                       patch_info->data.method);
-                       } else {
-                               target = mono_create_jit_trampoline (patch_info->data.method);
-                       }
+                       target = mono_create_jit_trampoline (patch_info->data.method);
                }
                break;
        case MONO_PATCH_INFO_SWITCH: {
@@ -2625,9 +2816,13 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
                target = mono_thread_interruption_request_flag ();
                break;
-       case MONO_PATCH_INFO_METHOD_RGCTX:
-               target = mono_method_lookup_rgctx (mono_class_vtable (domain, patch_info->data.method->klass), mini_method_get_context (patch_info->data.method)->method_inst);
+       case MONO_PATCH_INFO_METHOD_RGCTX: {
+               MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.method->klass);
+               g_assert (vtable);
+
+               target = mono_method_lookup_rgctx (vtable, mini_method_get_context (patch_info->data.method)->method_inst);
                break;
+       }
        case MONO_PATCH_INFO_BB_OVF:
        case MONO_PATCH_INFO_EXC_OVF:
        case MONO_PATCH_INFO_GOT_OFFSET:
@@ -2665,6 +2860,23 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        case MONO_PATCH_INFO_MONITOR_EXIT:
                target = mono_create_monitor_exit_trampoline ();
                break;
+#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
+       case MONO_PATCH_INFO_SEQ_POINT_INFO:
+               if (!run_cctors)
+                       /* AOT, not needed */
+                       target = NULL;
+               else
+                       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 ();
        }
@@ -2672,6 +2884,17 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        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;
+}
+
+#ifndef DISABLE_JIT
+
 static void
 mono_compile_create_vars (MonoCompile *cfg)
 {
@@ -2732,6 +2955,8 @@ mono_compile_create_vars (MonoCompile *cfg)
        mono_arch_create_vars (cfg);
 }
 
+#endif /* #ifndef DISABLE_JIT */
+
 void
 mono_print_code (MonoCompile *cfg, const char* msg)
 {
@@ -2743,101 +2968,12 @@ mono_print_code (MonoCompile *cfg, const char* msg)
 
 #ifndef DISABLE_JIT
 
-void
-mono_codegen (MonoCompile *cfg)
+static void
+mono_postprocess_patches (MonoCompile *cfg)
 {
        MonoJumpInfo *patch_info;
-       MonoBasicBlock *bb;
-       int i, max_epilog_size;
-       guint8 *code;
-
-       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               cfg->spill_count = 0;
-               /* we reuse dfn here */
-               /* bb->dfn = bb_count++; */
-
-               mono_arch_lowering_pass (cfg, bb);
-
-               if (cfg->opt & MONO_OPT_PEEPHOLE)
-                       mono_arch_peephole_pass_1 (cfg, bb);
-
-               if (!cfg->globalra)
-                       mono_local_regalloc (cfg, bb);
-
-               if (cfg->opt & MONO_OPT_PEEPHOLE)
-                       mono_arch_peephole_pass_2 (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);
-
-       if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
-               code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
-
-       cfg->code_len = code - cfg->native_code;
-       cfg->prolog_end = cfg->code_len;
-
-       mono_debug_open_method (cfg);
-
-       /* emit code all basic blocks */
-       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               bb->native_offset = cfg->code_len;
-               //if ((bb == cfg->bb_entry) || !(bb->region == -1 && !bb->dfn))
-                       mono_arch_output_basic_block (cfg, bb);
-
-               if (bb == cfg->bb_exit) {
-                       cfg->epilog_begin = cfg->code_len;
-
-                       if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
-                               code = cfg->native_code + cfg->code_len;
-                               code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
-                               cfg->code_len = code - cfg->native_code;
-                               g_assert (cfg->code_len < cfg->code_size);
-                       }
-
-                       mono_arch_emit_epilog (cfg);
-               }
-       }
-
-       mono_arch_emit_exceptions (cfg);
-
-       max_epilog_size = 0;
-
-       code = cfg->native_code + cfg->code_len;
-
-       /* we always allocate code in cfg->domain->code_mp to increase locality */
-       cfg->code_size = cfg->code_len + max_epilog_size;
-       /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
-
-       if (cfg->method->dynamic) {
-               guint unwindlen = 0;
-#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
-               unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
-#endif
-               /* Allocate the code into a separate memory pool so it can be freed */
-               cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
-               cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
-               mono_domain_lock (cfg->domain);
-               mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
-               mono_domain_unlock (cfg->domain);
-
-               code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size + unwindlen);
-       } else {
-               guint unwindlen = 0;
-#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
-               unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
-#endif
-               code = mono_domain_code_reserve (cfg->domain, cfg->code_size + unwindlen);
-       }
+       int i;
 
-       memcpy (code, cfg->native_code, cfg->code_len);
-       g_free (cfg->native_code);
-       cfg->native_code = code;
-       code = cfg->native_code + cfg->code_len;
-  
-       /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
        for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
                switch (patch_info->type) {
                case MONO_PATCH_INFO_ABS: {
@@ -2924,13 +3060,221 @@ mono_codegen (MonoCompile *cfg)
                        break;
                }
        }
+}
 
-#ifdef VALGRIND_JIT_REGISTER_MAP
-if (valgrind_register){
-               char* nm = mono_method_full_name (cfg->method, TRUE);
-               VALGRIND_JIT_REGISTER_MAP (nm, cfg->native_code, cfg->native_code + cfg->code_len);
-               g_free (nm);
-       }
+static void
+collect_pred_seq_points (MonoBasicBlock *bb, MonoInst *ins, GSList **next, int depth)
+{
+       int i;
+       MonoBasicBlock *in_bb;
+
+       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));
+               } else {
+                       /* Have to look at its predecessors */
+                       if (depth < 5)
+                               collect_pred_seq_points (in_bb, ins, next, depth + 1);
+               }
+       }
+}
+
+static void
+mono_save_seq_point_info (MonoCompile *cfg)
+{
+       MonoBasicBlock *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 */
+                               collect_pred_seq_points (bb, ins, next, 0);
+                       }
+
+                       last = ins;
+               }
+       }
+
+       if (cfg->verbose_level > 2) {
+               printf ("\nSEQ POINT MAP: \n");
+       }
+
+       for (i = 0; i < cfg->seq_points->len; ++i) {
+               SeqPoint *sp = &info->seq_points [i];
+               GSList *l;
+               int j, next_index;
+
+               sp->next_len = g_slist_length (next [i]);
+               sp->next = g_new (int, sp->next_len);
+               j = 0;
+               if (cfg->verbose_level > 2 && next [i]) {
+                       printf ("\t0x%x ->", sp->il_offset);
+                       for (l = next [i]; l; l = l->next) {
+                               next_index = GPOINTER_TO_UINT (l->data);
+                               printf (" 0x%x", info->seq_points [next_index].il_offset);
+                       }
+                       printf ("\n");
+               }
+               for (l = next [i]; l; l = l->next) {
+                       next_index = GPOINTER_TO_UINT (l->data);
+                       sp->next [j ++] = next_index;
+               }
+               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)
+{
+       MonoBasicBlock *bb;
+       int max_epilog_size;
+       guint8 *code;
+
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               cfg->spill_count = 0;
+               /* we reuse dfn here */
+               /* bb->dfn = bb_count++; */
+
+               mono_arch_lowering_pass (cfg, bb);
+
+               if (cfg->opt & MONO_OPT_PEEPHOLE)
+                       mono_arch_peephole_pass_1 (cfg, bb);
+
+               if (!cfg->globalra)
+                       mono_local_regalloc (cfg, bb);
+
+               if (cfg->opt & MONO_OPT_PEEPHOLE)
+                       mono_arch_peephole_pass_2 (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);
+
+       if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
+               code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
+
+       cfg->code_len = code - cfg->native_code;
+       cfg->prolog_end = cfg->code_len;
+
+       mono_debug_open_method (cfg);
+
+       /* emit code all basic blocks */
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               bb->native_offset = cfg->code_len;
+               //if ((bb == cfg->bb_entry) || !(bb->region == -1 && !bb->dfn))
+                       mono_arch_output_basic_block (cfg, bb);
+
+               if (bb == cfg->bb_exit) {
+                       cfg->epilog_begin = cfg->code_len;
+
+                       if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
+                               code = cfg->native_code + cfg->code_len;
+                               code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
+                               cfg->code_len = code - cfg->native_code;
+                               g_assert (cfg->code_len < cfg->code_size);
+                       }
+
+                       mono_arch_emit_epilog (cfg);
+               }
+       }
+
+       mono_arch_emit_exceptions (cfg);
+
+       max_epilog_size = 0;
+
+       code = cfg->native_code + cfg->code_len;
+
+       /* we always allocate code in cfg->domain->code_mp to increase locality */
+       cfg->code_size = cfg->code_len + max_epilog_size;
+       /* fixme: align to MONO_ARCH_CODE_ALIGNMENT */
+
+       if (cfg->method->dynamic) {
+               guint unwindlen = 0;
+#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
+               unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
+#endif
+               /* Allocate the code into a separate memory pool so it can be freed */
+               cfg->dynamic_info = g_new0 (MonoJitDynamicMethodInfo, 1);
+               cfg->dynamic_info->code_mp = mono_code_manager_new_dynamic ();
+               mono_domain_lock (cfg->domain);
+               mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
+               mono_domain_unlock (cfg->domain);
+
+               code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size + unwindlen);
+       } else {
+               guint unwindlen = 0;
+#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
+               unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
+#endif
+               code = mono_domain_code_reserve (cfg->domain, cfg->code_size + unwindlen);
+       }
+
+       memcpy (code, cfg->native_code, cfg->code_len);
+       g_free (cfg->native_code);
+       cfg->native_code = code;
+       code = cfg->native_code + cfg->code_len;
+  
+       /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
+       mono_postprocess_patches (cfg);
+
+#ifdef VALGRIND_JIT_REGISTER_MAP
+if (valgrind_register){
+               char* nm = mono_method_full_name (cfg->method, TRUE);
+               VALGRIND_JIT_REGISTER_MAP (nm, cfg->native_code, cfg->native_code + cfg->code_len);
+               g_free (nm);
+       }
 #endif
  
        if (cfg->verbose_level > 0) {
@@ -2964,10 +3308,12 @@ if (valgrind_register){
        } else {
                mono_domain_code_commit (cfg->domain, cfg->native_code, cfg->code_size, cfg->code_len);
        }
+       mono_profiler_code_buffer_new (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);
 #endif
@@ -2985,6 +3331,150 @@ compute_reachable (MonoBasicBlock *bb)
        }
 }
 
+static MonoJitInfo*
+create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
+{
+       MonoMethodHeader *header;
+       MonoJitInfo *jinfo;
+       int num_clauses;
+       int generic_info_size;
+
+       header = mono_method_get_header (method_to_compile);
+
+       if (cfg->generic_sharing_context)
+               generic_info_size = sizeof (MonoGenericJitInfo);
+       else
+               generic_info_size = 0;
+
+       if (COMPILE_LLVM (cfg))
+               num_clauses = cfg->llvm_ex_info_len;
+       else
+               num_clauses = header->num_clauses;
+
+       if (cfg->method->dynamic) {
+               jinfo = g_malloc0 (MONO_SIZEOF_JIT_INFO + (num_clauses * sizeof (MonoJitExceptionInfo)) +
+                               generic_info_size);
+       } else {
+               jinfo = mono_domain_alloc0 (cfg->domain, MONO_SIZEOF_JIT_INFO +
+                               (num_clauses * sizeof (MonoJitExceptionInfo)) +
+                               generic_info_size);
+       }
+
+       jinfo->method = cfg->method_to_register;
+       jinfo->code_start = cfg->native_code;
+       jinfo->code_size = cfg->code_len;
+       jinfo->used_regs = cfg->used_int_regs;
+       jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
+       jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
+       jinfo->num_clauses = num_clauses;
+       if (COMPILE_LLVM (cfg))
+               jinfo->from_llvm = TRUE;
+
+       if (cfg->generic_sharing_context) {
+               MonoInst *inst;
+               MonoGenericJitInfo *gi;
+
+               jinfo->has_generic_jit_info = 1;
+
+               gi = mono_jit_info_get_generic_jit_info (jinfo);
+               g_assert (gi);
+
+               gi->generic_sharing_context = cfg->generic_sharing_context;
+
+               if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
+                               mini_method_get_context (method_to_compile)->method_inst ||
+                               method_to_compile->klass->valuetype) {
+                       g_assert (cfg->rgctx_var);
+               }
+
+               gi->has_this = 1;
+
+               if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
+                               mini_method_get_context (method_to_compile)->method_inst ||
+                               method_to_compile->klass->valuetype) {
+                       inst = cfg->rgctx_var;
+                       g_assert (inst->opcode == OP_REGOFFSET);
+               } else {
+                       inst = cfg->args [0];
+               }
+
+               if (inst->opcode == OP_REGVAR) {
+                       gi->this_in_reg = 1;
+                       gi->this_reg = inst->dreg;
+               } else {
+                       g_assert (inst->opcode == OP_REGOFFSET);
+#ifdef TARGET_X86
+                       g_assert (inst->inst_basereg == X86_EBP);
+#elif defined(TARGET_AMD64)
+                       g_assert (inst->inst_basereg == X86_EBP || inst->inst_basereg == X86_ESP);
+#endif
+                       g_assert (inst->inst_offset >= G_MININT32 && inst->inst_offset <= G_MAXINT32);
+
+                       gi->this_in_reg = 0;
+                       gi->this_reg = inst->inst_basereg;
+                       gi->this_offset = inst->inst_offset;
+               }
+       }
+
+       if (COMPILE_LLVM (cfg)) {
+               if (num_clauses)
+                       memcpy (&jinfo->clauses [0], &cfg->llvm_ex_info [0], num_clauses * sizeof (MonoJitExceptionInfo));
+       } else if (header->num_clauses) {
+               int i;
+
+               for (i = 0; i < header->num_clauses; i++) {
+                       MonoExceptionClause *ec = &header->clauses [i];
+                       MonoJitExceptionInfo *ei = &jinfo->clauses [i];
+                       MonoBasicBlock *tblock;
+                       MonoInst *exvar;
+
+                       ei->flags = ec->flags;
+
+                       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];
+                               g_assert (tblock);
+                               ei->data.filter = cfg->native_code + tblock->native_offset;
+                       } else {
+                               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;
+               }
+       }
+
+       /* 
+        * Its possible to generate dwarf unwind info for xdebug etc, but not actually
+        * using it during runtime, hence the define.
+        */
+#ifdef MONO_ARCH_HAVE_XP_UNWIND
+       if (cfg->encoded_unwind_ops) {
+               jinfo->used_regs = mono_cache_unwind_info (cfg->encoded_unwind_ops, cfg->encoded_unwind_ops_len);
+               g_free (cfg->encoded_unwind_ops);
+       } else if (cfg->unwind_ops) {
+               guint32 info_len;
+               guint8 *unwind_info = mono_unwind_ops_encode (cfg->unwind_ops, &info_len);
+
+               jinfo->used_regs = mono_cache_unwind_info (unwind_info, info_len);
+               g_free (unwind_info);
+       }
+#endif
+
+       return jinfo;
+}
+
 /*
  * mini_method_compile:
  * @method: the method to compile
@@ -3003,12 +3493,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        MonoMethodHeader *header;
        guint8 *ip;
        MonoCompile *cfg;
-       MonoJitInfo *jinfo;
        int dfn, i, code_size_ratio;
        gboolean deadce_has_run = FALSE;
-       gboolean try_generic_shared;
+       gboolean try_generic_shared, try_llvm;
        MonoMethod *method_to_compile, *method_to_register;
-       int generic_info_size;
 
        mono_jit_stats.methods_compiled++;
        if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
@@ -3031,6 +3519,12 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                        mono_stats.generics_unsharable_methods++;
        }
 
+       try_llvm = TRUE;
+
+#ifndef ENABLE_LLVM
+       try_llvm = FALSE;
+#endif
+
  restart_compile:
        if (try_generic_shared) {
                MonoMethod *declaring_method;
@@ -3068,15 +3562,103 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        cfg->compile_aot = compile_aot;
        cfg->skip_visibility = method->skip_visibility;
        cfg->orig_method = method;
+       cfg->gen_seq_points = debug_options.gen_seq_points;
+       cfg->explicit_null_checks = debug_options.explicit_null_checks;
        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;
        }
 
+       if (cfg->generic_sharing_context) {
+               MonoGenericContext object_context = mono_method_construct_object_context (method_to_compile);
+
+               method_to_register = mono_class_inflate_generic_method (method_to_compile, &object_context);
+       } else {
+               g_assert (method == method_to_compile);
+               method_to_register = method;
+       }
+       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;
+               }
+       }
+
+       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 (FALSE && 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;
@@ -3087,6 +3669,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                 */
                cfg->disable_initlocals_opt = TRUE;
 
+               cfg->extend_live_ranges = TRUE;
+
                /* Temporarily disable this when running in the debugger until we have support
                 * for this in the debugger. */
                cfg->disable_omit_fp = TRUE;
@@ -3104,30 +3688,54 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                cfg->opt &= ~MONO_OPT_COPYPROP;
                cfg->opt &= ~MONO_OPT_CONSPROP;
                cfg->opt &= ~MONO_OPT_GSHARED;
+
+               /* This is needed for the soft debugger, which doesn't like code after the epilog */
+               cfg->disable_out_of_line_bblocks = TRUE;
        }
 
-       header = mono_method_get_header (method_to_compile);
-       if (!header) {
-               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);
-               if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
-                       mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
-               return cfg;
+       if (mono_using_xdebug) {
+               /* 
+                * Make each variable use its own register/stack slot and extend 
+                * their liveness to cover the whole method, making them displayable
+                * in gdb even after they are dead.
+                */
+               cfg->disable_reuse_registers = TRUE;
+               cfg->disable_reuse_stack_slots = TRUE;
+               cfg->extend_live_ranges = TRUE;
+               cfg->compute_precise_live_ranges = TRUE;
+       }
+
+       mini_gc_init_gc_map (cfg);
+
+       if (COMPILE_LLVM (cfg)) {
+               cfg->opt |= MONO_OPT_ABCREM;
        }
 
        if (getenv ("MONO_VERBOSE_METHOD")) {
-               if (strcmp (cfg->method->name, getenv ("MONO_VERBOSE_METHOD")) == 0)
-                       cfg->verbose_level = 4;
+               char *name = getenv ("MONO_VERBOSE_METHOD");
+
+               if (strchr (name, '.') || strchr (name, ':')) {
+                       MonoMethodDesc *desc;
+                       
+                       desc = mono_method_desc_new (name, TRUE);
+                       if (mono_method_desc_full_match (desc, cfg->method)) {
+                               cfg->verbose_level = 4;
+                       }
+                       mono_method_desc_free (desc);
+               } else {
+                       if (strcmp (cfg->method->name, getenv ("MONO_VERBOSE_METHOD")) == 0)
+                               cfg->verbose_level = 4;
+               }
        }
 
        ip = (guint8 *)header->code;
 
        cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * header->max_stack);
 
-       if (cfg->verbose_level > 2) {
-               if (cfg->generic_sharing_context)
+       if (cfg->verbose_level > 0) {
+               if (COMPILE_LLVM (cfg))
+                       g_print ("converting llvm method %s\n", mono_method_full_name (method, TRUE));
+               else if (cfg->generic_sharing_context)
                        g_print ("converting shared method %s\n", mono_method_full_name (method, TRUE));
                else
                        g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
@@ -3198,6 +3806,10 @@ 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))
+               return cfg;
+
        /*
         * create MonoInst* which represents arguments and local variables
         */
@@ -3223,8 +3835,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
                if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
                        MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
-               if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
-                       mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
                /* cfg contains the details of the failure, so let the caller cleanup */
                return cfg;
        }
@@ -3232,9 +3842,50 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        mono_jit_stats.basic_blocks += cfg->num_bblocks;
        mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
 
+       if (COMPILE_LLVM (cfg)) {
+               MonoInst *ins;
+
+               /* The IR has to be in SSA form for LLVM */
+               cfg->opt |= MONO_OPT_SSA;
+
+               // FIXME:
+               if (cfg->ret) {
+                       // Allow SSA on the result value
+                       cfg->ret->flags &= ~MONO_INST_VOLATILE;
+
+                       // Add an explicit return instruction referencing the return value
+                       MONO_INST_NEW (cfg, ins, OP_SETRET);
+                       ins->sreg1 = cfg->ret->dreg;
+
+                       MONO_ADD_INS (cfg->bb_exit, ins);
+               }
+
+               cfg->opt &= ~MONO_OPT_LINEARS;
+
+               /* FIXME: */
+               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);*/
 
-       mono_decompose_long_opts (cfg);
+       if (!COMPILE_LLVM (cfg))
+               mono_decompose_long_opts (cfg);
 
        /* Should be done before branch opts */
        if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
@@ -3247,7 +3898,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        mono_handle_global_vregs (cfg);
        if (cfg->opt & MONO_OPT_DEADCE)
                mono_local_deadce (cfg);
-       mono_if_conversion (cfg);
+       /* Disable this for LLVM to make the IR easier to handle */
+       if (!COMPILE_LLVM (cfg))
+               mono_if_conversion (cfg);
 
        if ((cfg->opt & MONO_OPT_SSAPRE) || cfg->globalra)
                mono_remove_critical_edges (cfg);
@@ -3255,6 +3908,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        /* 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) {
@@ -3275,6 +3930,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                                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)
@@ -3303,11 +3960,16 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                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
@@ -3316,7 +3978,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
 #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
@@ -3336,7 +3998,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
 
        if ((cfg->opt & MONO_OPT_CONSPROP) || (cfg->opt & MONO_OPT_COPYPROP)) {
-               if (cfg->comp_done & MONO_COMP_SSA) {
+               if (cfg->comp_done & MONO_COMP_SSA && !COMPILE_LLVM (cfg)) {
 #ifndef DISABLE_SSA
                        mono_ssa_cprop (cfg);
 #endif
@@ -3344,7 +4006,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
 
 #ifndef DISABLE_SSA
-       if (cfg->comp_done & MONO_COMP_SSA) {                   
+       if (cfg->comp_done & MONO_COMP_SSA && !COMPILE_LLVM (cfg)) {
                //mono_ssa_strength_reduction (cfg);
 
                if (cfg->opt & MONO_OPT_SSAPRE) {
@@ -3389,6 +4051,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
 #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))
+                       mono_perform_abc_removal (cfg);
+       }
+
        /* after SSA removal */
        if (parts == 3) {
                if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
@@ -3397,9 +4064,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
 
 #ifdef MONO_ARCH_SOFT_FLOAT
-       mono_decompose_soft_float (cfg);
+       if (!COMPILE_LLVM (cfg))
+               mono_decompose_soft_float (cfg);
 #endif
-       mono_decompose_vtype_opts (cfg);
+       if (!COMPILE_LLVM (cfg))
+               mono_decompose_vtype_opts (cfg);
        if (cfg->flags & MONO_CFG_HAS_ARRAY_ACCESS)
                mono_decompose_array_access_opts (cfg);
 
@@ -3424,12 +4093,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                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);
 
@@ -3459,19 +4124,22 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                }
        }
 
-       //mono_print_code (cfg);
+       //mono_print_code (cfg, "");
 
     //print_dfn (cfg);
        
        /* variables are allocated after decompose, since decompose could create temps */
-       if (!cfg->globalra)
+       if (!cfg->globalra && !COMPILE_LLVM (cfg)) {
                mono_arch_allocate_vars (cfg);
+               if (cfg->exception_type)
+                       return cfg;
+       }
 
        {
                MonoBasicBlock *bb;
                gboolean need_local_opts;
 
-               if (!cfg->globalra) {
+               if (!cfg->globalra && !COMPILE_LLVM (cfg)) {
                        mono_spill_global_vars (cfg, &need_local_opts);
 
                        if (need_local_opts || cfg->compile_aot) {
@@ -3522,153 +4190,75 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                }
        }
 
-       mono_codegen (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->generic_sharing_context)
-               generic_info_size = sizeof (MonoGenericJitInfo);
-       else
-               generic_info_size = 0;
+       if (COMPILE_LLVM (cfg)) {
+#ifdef ENABLE_LLVM
+               char *nm;
 
-       if (cfg->method->dynamic) {
-               jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
-                               generic_info_size);
-       } else {
-               jinfo = mono_domain_alloc0 (cfg->domain, sizeof (MonoJitInfo) +
-                               (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
-                               generic_info_size);
-       }
-
-       if (cfg->generic_sharing_context) {
-               MonoGenericContext object_context = mono_method_construct_object_context (method_to_compile);
-
-               method_to_register = mono_class_inflate_generic_method (method_to_compile, &object_context);
-       } else {
-               g_assert (method == method_to_compile);
-               method_to_register = method;
-       }
-
-       jinfo->method = method_to_register;
-       jinfo->code_start = cfg->native_code;
-       jinfo->code_size = cfg->code_len;
-       jinfo->used_regs = cfg->used_int_regs;
-       jinfo->domain_neutral = (cfg->opt & MONO_OPT_SHARED) != 0;
-       jinfo->cas_inited = FALSE; /* initialization delayed at the first stalk walk using this method */
-       jinfo->num_clauses = header->num_clauses;
-
-       if (cfg->generic_sharing_context) {
-               MonoInst *inst;
-               MonoGenericJitInfo *gi;
-
-               jinfo->has_generic_jit_info = 1;
-
-               gi = mono_jit_info_get_generic_jit_info (jinfo);
-               g_assert (gi);
-
-               gi->generic_sharing_context = cfg->generic_sharing_context;
-
-               if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
-                               mini_method_get_context (method_to_compile)->method_inst ||
-                               method_to_compile->klass->valuetype) {
-                       g_assert (cfg->rgctx_var);
+               /* The IR has to be in SSA form for LLVM */
+               if (!(cfg->comp_done & MONO_COMP_SSA)) {
+                       cfg->exception_message = g_strdup ("SSA disabled.");
+                       cfg->disable_llvm = TRUE;
                }
 
-               gi->has_this = 1;
+               if (cfg->flags & MONO_CFG_HAS_ARRAY_ACCESS)
+                       mono_decompose_array_access_opts (cfg);
 
-               if ((method_to_compile->flags & METHOD_ATTRIBUTE_STATIC) ||
-                               mini_method_get_context (method_to_compile)->method_inst ||
-                               method_to_compile->klass->valuetype) {
-                       inst = cfg->rgctx_var;
-                       g_assert (inst->opcode == OP_REGOFFSET);
-               } else {
-                       inst = cfg->args [0];
+               if (!cfg->disable_llvm)
+                       mono_llvm_emit_method (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);
+                       }
+                       InterlockedIncrement (&methods_without_llvm);
+                       mono_destroy_compile (cfg);
+                       try_llvm = FALSE;
+                       goto restart_compile;
                }
 
-               if (inst->opcode == OP_REGVAR) {
-                       gi->this_in_reg = 1;
-                       gi->this_reg = inst->dreg;
-               } else {
-                       g_assert (inst->opcode == OP_REGOFFSET);
-#ifdef __i386__
-                       g_assert (inst->inst_basereg == X86_EBP);
-#elif defined(__x86_64__)
-                       g_assert (inst->inst_basereg == X86_EBP || inst->inst_basereg == X86_ESP);
-#endif
-                       g_assert (inst->inst_offset >= G_MININT32 && inst->inst_offset <= G_MAXINT32);
+               InterlockedIncrement (&methods_with_llvm);
 
-                       gi->this_in_reg = 0;
-                       gi->this_reg = inst->inst_basereg;
-                       gi->this_offset = inst->inst_offset;
+               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, 
+                                        cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
+                       g_free (nm);
                }
+#endif
+       } else {
+               mono_codegen (cfg);
        }
 
-       if (header->num_clauses) {
-               int i;
-
-               for (i = 0; i < header->num_clauses; i++) {
-                       MonoExceptionClause *ec = &header->clauses [i];
-                       MonoJitExceptionInfo *ei = &jinfo->clauses [i];
-                       MonoBasicBlock *tblock;
-                       MonoInst *exvar;
-
-                       ei->flags = ec->flags;
-
-                       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];
-                               g_assert (tblock);
-                               ei->data.filter = cfg->native_code + tblock->native_offset;
-                       } else {
-                               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 (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);
        }
 
-       /* 
-        * Its possible to generate dwarf unwind info for xdebug etc, but not actually
-        * using it during runtime, hence the define.
-        */
-#ifdef MONO_ARCH_HAVE_XP_UNWIND
-       if (cfg->unwind_ops) {
-               guint32 info_len;
-               guint8 *unwind_info = mono_unwind_ops_encode (cfg->unwind_ops, &info_len);
+       cfg->jit_info = create_jit_info (cfg, method_to_compile);
 
-               jinfo->used_regs = mono_cache_unwind_info (unwind_info, info_len);
-               g_free (unwind_info);
+#ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
+       if (cfg->extend_live_ranges) {
+               /* Extend live ranges to cover the whole method */
+               for (i = 0; i < cfg->num_varinfo; ++i)
+                       MONO_VARINFO (cfg, i)->live_range_end = cfg->code_len;
        }
 #endif
 
-       cfg->jit_info = jinfo;
-#if defined(__arm__)
-       mono_arch_fixup_jinfo (cfg);
-#endif
-
        mono_save_xdebug_info (cfg);
 
+       mini_gc_create_gc_map (cfg);
+       mono_save_seq_point_info (cfg);
+
        if (!cfg->compile_aot) {
                mono_domain_lock (cfg->domain);
-               mono_jit_info_table_add (cfg->domain, jinfo);
+               mono_jit_info_table_add (cfg->domain, cfg->jit_info);
 
                if (cfg->method->dynamic)
-                       mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = jinfo;
+                       mono_dynamic_code_hash_lookup (cfg->domain, cfg->method)->ji = cfg->jit_info;
                mono_domain_unlock (cfg->domain);
        }
 
@@ -3692,8 +4282,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
                MONO_PROBE_METHOD_COMPILE_END (method, TRUE);
-       if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
-               mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
 
        return cfg;
 }
@@ -3751,15 +4339,17 @@ lookup_method (MonoDomain *domain, MonoMethod *method)
 }
 
 static gpointer
-mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
+mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt, MonoException **jit_ex)
 {
        MonoCompile *cfg;
        gpointer code = NULL;
-       MonoJitInfo *info;
+       MonoJitInfo *jinfo, *info;
        MonoVTable *vtable;
+       MonoException *ex = NULL;
+       guint32 prof_options;
 
 #ifdef MONO_USE_AOT_COMPILER
-       if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
+       if (opt & MONO_OPT_AOT) {
                MonoDomain *domain = mono_domain_get ();
 
                mono_class_init (method->klass);
@@ -3768,6 +4358,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                        vtable = mono_class_vtable (domain, method->klass);
                        g_assert (vtable);
                        mono_runtime_class_init (vtable);
+
                        return code;
                }
        }
@@ -3782,7 +4373,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                        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);
@@ -3832,8 +4423,16 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                return NULL;
        }
 
-       if (mono_aot_only)
-               g_error ("Attempting to JIT compile method '%s' while running with --aot-only.\n", mono_method_full_name (method, TRUE));
+       if (mono_aot_only) {
+               char *fullname = mono_method_full_name (method, TRUE);
+               char *msg = g_strdup_printf ("Attempting to JIT compile method '%s' while running with --aot-only.\n", fullname);
+
+               *jit_ex = mono_get_exception_execution_engine (msg);
+               g_free (fullname);
+               g_free (msg);
+               
+               return NULL;
+       }
 
        cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
 
@@ -3847,7 +4446,6 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        case MONO_EXCEPTION_BAD_IMAGE: {
                /* Throw a type load exception if needed */
                MonoLoaderError *error = mono_loader_get_last_error ();
-               MonoException *ex;
 
                if (error) {
                        ex = mono_loader_error_prepare_exception (error);
@@ -3869,34 +4467,20 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                                        g_assert_not_reached ();
                        }
                }
-               mono_destroy_compile (cfg);
-               mono_raise_exception (ex);
                break;
        }
-       case MONO_EXCEPTION_INVALID_PROGRAM: {
-               MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
-               mono_destroy_compile (cfg);
-               mono_raise_exception (ex);
+       case MONO_EXCEPTION_INVALID_PROGRAM:
+               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
                break;
-       }
-       case MONO_EXCEPTION_UNVERIFIABLE_IL: {
-               MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
-               mono_destroy_compile (cfg);
-               mono_raise_exception (ex);
+       case MONO_EXCEPTION_UNVERIFIABLE_IL:
+               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
                break;
-       }
-       case MONO_EXCEPTION_METHOD_ACCESS: {
-               MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
-               mono_destroy_compile (cfg);
-               mono_raise_exception (ex);
+       case MONO_EXCEPTION_METHOD_ACCESS:
+               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", cfg->exception_message);
                break;
-       }
-       case MONO_EXCEPTION_FIELD_ACCESS: {
-               MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
-               mono_destroy_compile (cfg);
-               mono_raise_exception (ex);
+       case MONO_EXCEPTION_FIELD_ACCESS:
+               ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "FieldAccessException", cfg->exception_message);
                break;
-       }
        /* this can only be set if the security manager is active */
        case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
                MonoSecurityManager* secman = mono_security_manager_get_methods ();
@@ -3907,22 +4491,30 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                args [1] = &method;
                mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
 
-               mono_destroy_compile (cfg);
-               cfg = NULL;
-
-               mono_raise_exception ((MonoException*)exc);
+               ex = (MonoException*)exc;
+               break;
        }
        case MONO_EXCEPTION_OBJECT_SUPPLIED: {
                MonoException *exp = cfg->exception_ptr;
                MONO_GC_UNREGISTER_ROOT (cfg->exception_ptr);
-               mono_destroy_compile (cfg);
-               mono_raise_exception (exp);
+
+               ex = exp;
                break;
        }
        default:
                g_assert_not_reached ();
        }
 
+       if (ex) {
+               if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
+                       mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
+
+               mono_destroy_compile (cfg);
+               *jit_ex = ex;
+
+               return NULL;
+       }
+
        mono_loader_lock (); /*FIXME lookup_method_inner requires the loader lock*/
        mono_domain_lock (target_domain);
 
@@ -3951,6 +4543,10 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                mono_domain_jit_code_hash_unlock (target_domain);
        }
 
+       jinfo = cfg->jit_info;
+
+       prof_options = cfg->prof_options;
+
        mono_destroy_compile (cfg);
 
        if (domain_jit_info (target_domain)->jump_target_hash) {
@@ -3979,16 +4575,25 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                g_assert (exc);
                mono_raise_exception (exc);
        }
+
+       if (prof_options & MONO_PROFILE_JIT_COMPILATION) {
+               if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
+                       /* 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_runtime_class_init (vtable);
        return code;
 }
 
 static gpointer
-mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
+mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex)
 {
        MonoDomain *target_domain, *domain = mono_domain_get ();
        MonoJitInfo *info;
-       gpointer p;
+       gpointer code, p;
        MonoJitICallInfo *callinfo = NULL;
 
        /*
@@ -4020,12 +4625,17 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
 
                        mono_jit_stats.methods_lookups++;
                        vtable = mono_class_vtable (domain, method->klass);
+                       g_assert (vtable);
                        mono_runtime_class_init (vtable);
                        return mono_create_ftnptr (target_domain, info->code_start);
                }
        }
 
-       p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
+       code = mono_jit_compile_method_inner (method, target_domain, opt, ex);
+       if (!code)
+               return NULL;
+
+       p = mono_create_ftnptr (target_domain, code);
 
        if (callinfo) {
                mono_jit_lock ();
@@ -4040,10 +4650,19 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
        return p;
 }
 
-static gpointer
+gpointer
 mono_jit_compile_method (MonoMethod *method)
 {
-       return mono_jit_compile_method_with_opt (method, default_opt);
+       MonoException *ex = NULL;
+       gpointer code;
+
+       code = mono_jit_compile_method_with_opt (method, default_opt, &ex);
+       if (!code) {
+               g_assert (ex);
+               mono_raise_exception (ex);
+       }
+
+       return code;
 }
 
 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
@@ -4079,6 +4698,7 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
        g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
        mono_internal_hash_table_remove (&domain->jit_code_hash, method);
        g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
+       g_hash_table_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
        mono_domain_unlock (domain);
 
 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
@@ -4109,7 +4729,7 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
 }
 
 gpointer
-mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
+mono_jit_find_compiled_method_with_jit_info (MonoDomain *domain, MonoMethod *method, MonoJitInfo **ji)
 {
        MonoDomain *target_domain;
        MonoJitInfo *info;
@@ -4124,13 +4744,32 @@ mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
                /* We can't use a domain specific method in another domain */
                if (! ((domain != target_domain) && !info->domain_neutral)) {
                        mono_jit_stats.methods_lookups++;
+                       if (ji)
+                               *ji = info;
                        return info->code_start;
                }
        }
 
+       if (ji)
+               *ji = NULL;
        return NULL;
 }
 
+gpointer
+mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
+{
+       return mono_jit_find_compiled_method_with_jit_info (domain, method, NULL);
+}
+
+typedef struct {
+       MonoMethod *method;
+       gpointer compiled_method;
+       gpointer runtime_invoke;
+       MonoVTable *vtable;
+       MonoDynCallInfo *dyn_call_info;
+       MonoClass *ret_box_class;
+} RuntimeInvokeInfo;
+
 /**
  * mono_jit_runtime_invoke:
  * @method: the method to invoke
@@ -4141,68 +4780,224 @@ mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
 static MonoObject*
 mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
 {
-       MonoMethod *to_compile;
        MonoMethod *invoke;
        MonoObject *(*runtime_invoke) (MonoObject *this, void **params, MonoObject **exc, void* compiled_method);
-       void* compiled_method;
-       MonoVTable *vtable;
-
+       MonoDomain *domain = mono_domain_get ();
+       MonoJitDomainInfo *domain_info;
+       RuntimeInvokeInfo *info, *info2;
+       
        if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
                g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
                return NULL;
        }
 
-       if (mono_method_needs_static_rgctx_invoke (method, FALSE))
-               to_compile = mono_marshal_get_static_rgctx_invoke (method);
-       else
-               to_compile = method;
+       domain_info = domain_jit_info (domain);
 
-       /* Special case parameterless ctors to speed up Activator.CreateInstance () */
-       if (method->flags & (METHOD_ATTRIBUTE_SPECIAL_NAME | METHOD_ATTRIBUTE_RT_SPECIAL_NAME) && !strcmp (method->name, ".ctor") && mono_method_signature (method)->param_count == 0 && !method->klass->valuetype) {
-               MonoJitDomainInfo *domain_info = domain_jit_info (mono_domain_get ());
+       mono_domain_lock (domain);
+       info = g_hash_table_lookup (domain_info->runtime_invoke_hash, method);
+       mono_domain_unlock (domain);            
 
-               if (!domain_info->ctor_runtime_invoke) {
-                       invoke = mono_marshal_get_runtime_invoke (method, FALSE);
-                       domain_info->ctor_runtime_invoke = mono_jit_compile_method (invoke);
+       if (!info) {
+               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;
+                       }
                }
 
-               runtime_invoke = domain_info->ctor_runtime_invoke;
-       } else {
+               info = g_new0 (RuntimeInvokeInfo, 1);
+
                invoke = mono_marshal_get_runtime_invoke (method, FALSE);
-               runtime_invoke = mono_jit_compile_method (invoke);
+               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) &&
+                       (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
+                       /* 
+                        * Array Get/Set/Address methods. The JIT implements them using inline code 
+                        * inside the runtime invoke wrappers, so no need to compile them.
+                        */
+                       info->compiled_method = NULL;
+               } else {
+                       MonoException *jit_ex = NULL;
+
+                       info->compiled_method = mono_jit_compile_method_with_opt (method, default_opt, &jit_ex);
+                       if (!info->compiled_method) {
+                               g_free (info);
+                               g_assert (jit_ex);
+                               if (exc) {
+                                       *exc = (MonoObject*)jit_ex;
+                                       return NULL;
+                               } else {
+                                       mono_raise_exception (jit_ex);
+                               }
+                       }
+
+                       if (mono_method_needs_static_rgctx_invoke (method, FALSE))
+                               info->compiled_method = mono_create_static_rgctx_trampoline (method, info->compiled_method);
+               }
+
+               /*
+                * We want to avoid AOTing 1000s of runtime-invoke wrappers when running
+                * in full-aot mode, so we use a slower, but more generic wrapper if
+                * possible, built on top of the OP_DYN_CALL opcode provided by the JIT.
+                */
+#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
+               if (mono_aot_only || debug_options.dyn_runtime_invoke) {
+                       MonoMethodSignature *sig = mono_method_signature (method);
+                       gboolean supported = TRUE;
+                       int i;
+
+                       if (method->string_ctor)
+                               sig = mono_marshal_get_string_ctor_signature (method);
+
+                       for (i = 0; i < sig->param_count; ++i) {
+                               MonoType *t = sig->params [i];
+
+                               if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
+                                       supported = FALSE;
+                       }
+
+                       if (method->klass->contextbound || !info->compiled_method)
+                               supported = FALSE;
+
+                       if (supported)
+                               info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
+
+                       if (info->dyn_call_info) {
+                               switch (sig->ret->type) {
+                               case MONO_TYPE_VOID:
+                                       break;
+                               case MONO_TYPE_I1:
+                               case MONO_TYPE_U1:
+                               case MONO_TYPE_I2:
+                               case MONO_TYPE_U2:
+                               case MONO_TYPE_I4:
+                               case MONO_TYPE_U4:
+                               case MONO_TYPE_I:
+                               case MONO_TYPE_U:
+                               case MONO_TYPE_I8:
+                               case MONO_TYPE_U8:
+                               case MONO_TYPE_BOOLEAN:
+                               case MONO_TYPE_CHAR:
+                               case MONO_TYPE_R4:
+                               case MONO_TYPE_R8:
+                                       info->ret_box_class = mono_class_from_mono_type (sig->ret);
+                                       break;
+                               case MONO_TYPE_PTR:
+                                       info->ret_box_class = mono_defaults.int_class;
+                                       break;
+                               case MONO_TYPE_STRING:
+                               case MONO_TYPE_CLASS:  
+                               case MONO_TYPE_ARRAY:
+                               case MONO_TYPE_SZARRAY:
+                               case MONO_TYPE_OBJECT:
+                                       break;
+                               case MONO_TYPE_GENERICINST:
+                                       if (!MONO_TYPE_IS_REFERENCE (sig->ret))
+                                               info->ret_box_class = mono_class_from_mono_type (sig->ret);
+                                       break;
+                               case MONO_TYPE_VALUETYPE:
+                                       info->ret_box_class = mono_class_from_mono_type (sig->ret);
+                                       break;
+                               default:
+                                       g_assert_not_reached ();
+                                       break;
+                               }
+                       }
+               }
+#endif
+
+               if (!info->dyn_call_info)
+                       info->runtime_invoke = mono_jit_compile_method (invoke);
+
+               mono_domain_lock (domain);
+               info2 = g_hash_table_lookup (domain_info->runtime_invoke_hash, method);
+               if (info2) {
+                       g_free (info);
+                       info = info2;
+               } else {
+                       g_hash_table_insert (domain_info->runtime_invoke_hash, method, info);
+               }
+               mono_domain_unlock (domain);
        }
 
-       /* We need this here becuase mono_marshal_get_runtime_invoke can be place 
-        * the helper method in System.Object and not the target class
+       runtime_invoke = info->runtime_invoke;
+
+       /*
+        * We need this here because mono_marshal_get_runtime_invoke can place 
+        * the helper method in System.Object and not the target class.
         */
-       vtable = mono_class_vtable (mono_domain_get (), method->klass);
-       g_assert (vtable);
-       mono_runtime_class_init (vtable);
+       mono_runtime_class_init (info->vtable);
+
+#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
+       if (info->dyn_call_info) {
+               MonoMethodSignature *sig = mono_method_signature (method);
+               gpointer *args;
+               static RuntimeInvokeDynamicFunction dyn_runtime_invoke;
+               int i, pindex;
+               guint8 buf [128];
+               guint8 retval [128];
+
+               if (!dyn_runtime_invoke) {
+                       invoke = mono_marshal_get_runtime_invoke_dynamic ();
+                       dyn_runtime_invoke = mono_jit_compile_method (invoke);
+               }
 
-       if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
-               (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
-               /* 
-                * Array Get/Set/Address methods. The JIT implements them using inline code 
-                * inside the runtime invoke wrappers, so no need to compile them.
-                */
-               compiled_method = NULL;
-       } else {
-               compiled_method = mono_jit_compile_method (to_compile);
+               /* Convert the arguments to the format expected by start_dyn_call () */
+               args = g_alloca ((sig->param_count + sig->hasthis) * sizeof (gpointer));
+               pindex = 0;
+               if (sig->hasthis)
+                       args [pindex ++] = &obj;
+               for (i = 0; i < sig->param_count; ++i) {
+                       MonoType *t = sig->params [i];
+
+                       if (t->byref) {
+                               args [pindex ++] = &params [i];
+                       } else if (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR) {
+                               args [pindex ++] = &params [i];
+                       } else {
+                               args [pindex ++] = params [i];
+                       }
+               }
+
+               //printf ("M: %s\n", mono_method_full_name (method, TRUE));
+
+               mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
+
+               dyn_runtime_invoke (buf, exc, info->compiled_method);
+
+               mono_arch_finish_dyn_call (info->dyn_call_info, buf);
+
+               if (info->ret_box_class)
+                       return mono_value_box (domain, info->ret_box_class, retval);
+               else
+                       return *(MonoObject**)retval;
        }
-       return runtime_invoke (obj, params, exc, compiled_method);
+#endif
+
+       return runtime_invoke (obj, params, exc, info->compiled_method);
 }
 
 void
 SIG_HANDLER_SIGNATURE (mono_sigfpe_signal_handler)
 {
        MonoException *exc = NULL;
-#ifndef MONO_ARCH_USE_SIGACTION
+       MonoJitInfo *ji;
+#if !(defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32))
        void *info = NULL;
 #endif
        GET_CONTEXT;
 
-       if (mono_chain_signal (SIG_HANDLER_PARAMS))
-               return;
+       ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
 
 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
        if (mono_arch_is_int_overflow (ctx, info))
@@ -4212,6 +5007,13 @@ SIG_HANDLER_SIGNATURE (mono_sigfpe_signal_handler)
 #else
        exc = mono_get_exception_divide_by_zero ();
 #endif
+
+       if (!ji) {
+               if (mono_chain_signal (SIG_HANDLER_PARAMS))
+                       return;
+
+               mono_handle_native_sigsegv (SIGSEGV, ctx);
+       }
        
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
@@ -4238,6 +5040,23 @@ SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler)
 
        GET_CONTEXT;
 
+#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
+       if (mono_arch_is_single_step_event (info, ctx)) {
+               mono_debugger_agent_single_step_event (ctx);
+               return;
+       } else if (mono_arch_is_breakpoint_event (info, ctx)) {
+               mono_debugger_agent_breakpoint_hit (ctx);
+               return;
+       }
+#endif
+
+#ifndef HOST_WIN32
+       if (mono_aot_is_pagefault (info->si_addr)) {
+               mono_aot_handle_pagefault (info->si_addr);
+               return;
+       }
+#endif
+
        /* The thread might no be registered with the runtime */
        if (!mono_domain_get () || !jit_tls) {
                if (mono_chain_signal (SIG_HANDLER_PARAMS))
@@ -4311,7 +5130,7 @@ mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, Mon
        guint8 *addr = NULL;
 
        if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
-               return mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
+               return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
                        domain, NULL);
        }
 
@@ -4326,7 +5145,7 @@ mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, Mon
 }
 
 #ifdef MONO_ARCH_HAVE_IMT
-static gpointer
+static G_GNUC_UNUSED gpointer
 mini_get_imt_trampoline (void)
 {
        static gpointer tramp = NULL;
@@ -4336,16 +5155,15 @@ mini_get_imt_trampoline (void)
 }
 #endif
 
-#ifdef MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
 gpointer
-mini_get_vtable_trampoline (void)
+mini_get_vtable_trampoline (int slot_index)
 {
        static gpointer tramp = NULL;
+
        if (!tramp)
                tramp = mono_create_specific_trampoline (MONO_FAKE_VTABLE_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
        return tramp;
 }
-#endif
 
 static void
 mini_parse_debug_options (void)
@@ -4375,9 +5193,19 @@ mini_parse_debug_options (void)
                        debug_options.suspend_on_sigsegv = TRUE;
                else if (!strcmp (arg, "dont-free-domains"))
                        mono_dont_free_domains = TRUE;
+               else if (!strcmp (arg, "dyn-runtime-invoke"))
+                       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 if (!strcmp (arg, "init-stacks"))
+                       debug_options.init_stacks = 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'\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', 'init-stacks'\n");
                        exit (1);
                }
        }
@@ -4390,6 +5218,45 @@ mini_get_debug_options (void)
 {
        return &debug_options;
 }
+
+static gpointer
+mini_create_ftnptr (MonoDomain *domain, gpointer addr)
+{
+#ifdef __ia64__
+       gpointer *desc;
+
+       desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
+
+       desc [0] = addr;
+       desc [1] = NULL;
+
+       return desc;
+#elif defined(__ppc64__) || defined(__powerpc64__)
+       gpointer *desc;
+
+       desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
+
+       desc [0] = addr;
+       desc [1] = NULL;
+       desc [2] = NULL;
+
+       return desc;
+#else
+       return addr;
+#endif
+}
+
+static gpointer
+mini_get_addr_from_ftnptr (gpointer descr)
+{
+#if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
+       return *(gpointer*)descr;
+#else
+       return descr;
+#endif
+}      
+
+static void runtime_invoke_info_free (gpointer value);
  
 static void
 mini_create_jit_domain_info (MonoDomain *domain)
@@ -4400,6 +5267,10 @@ mini_create_jit_domain_info (MonoDomain *domain)
        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->llvm_vcall_trampoline_hash = g_hash_table_new (mono_aligned_addr_hash, NULL);
+       info->runtime_invoke_hash = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
+       info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, g_free);
+       info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
 
        domain->runtime_info = info;
 }
@@ -4418,6 +5289,18 @@ dynamic_method_info_free (gpointer key, gpointer value, gpointer user_data)
        g_free (di);
 }
 
+static void
+runtime_invoke_info_free (gpointer value)
+{
+       RuntimeInvokeInfo *info = (RuntimeInvokeInfo*)value;
+
+#ifdef MONO_ARCH_DYN_CALL_SUPPORTED
+       if (info->dyn_call_info)
+               mono_arch_dyn_call_free (info->dyn_call_info);
+#endif
+       g_free (info);
+}
+
 static void
 mini_free_jit_domain_info (MonoDomain *domain)
 {
@@ -4441,6 +5324,15 @@ mini_free_jit_domain_info (MonoDomain *domain)
        g_hash_table_destroy (info->jump_trampoline_hash);
        g_hash_table_destroy (info->jit_trampoline_hash);
        g_hash_table_destroy (info->delegate_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);
 
        g_free (domain->runtime_info);
        domain->runtime_info = NULL;
@@ -4450,6 +5342,7 @@ MonoDomain *
 mini_init (const char *filename, const char *runtime_version)
 {
        MonoDomain *domain;
+       MonoRuntimeCallbacks callbacks;
 
        MONO_PROBE_VES_INIT_BEGIN ();
 
@@ -4466,30 +5359,69 @@ mini_init (const char *filename, const char *runtime_version)
 
        InitializeCriticalSection (&jit_mutex);
 
+#ifdef MONO_DEBUGGER_SUPPORTED
+       if (mini_debug_running_inside_mdb ())
+               mini_debugger_init ();
+#endif
+
+#ifdef MONO_ARCH_HAVE_TLS_GET
+       mono_runtime_set_has_tls_get (TRUE);
+#else
+       mono_runtime_set_has_tls_get (FALSE);
+#endif
+
        if (!global_codeman)
                global_codeman = mono_code_manager_new ();
        jit_icall_name_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
+       memset (&callbacks, 0, sizeof (callbacks));
+       callbacks.create_ftnptr = mini_create_ftnptr;
+       callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
+       callbacks.get_runtime_build_info = mono_get_runtime_build_info;
+
+#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;
+               }
+       }
+#endif
+
+       mono_install_callbacks (&callbacks);
+       
        mono_arch_cpu_init ();
 
        mono_arch_init ();
 
        mono_unwind_init ();
 
+       mini_gc_init ();
+
+       if (getenv ("MONO_DEBUG") != NULL)
+               mini_parse_debug_options ();
+
        if (getenv ("MONO_XDEBUG")) {
-               mono_xdebug_init ();
+               char *xdebug_opts = getenv ("MONO_XDEBUG");
+               mono_xdebug_init (xdebug_opts);
                /* So methods for multiple domains don't have the same address */
                mono_dont_free_domains = TRUE;
+               mono_using_xdebug = TRUE;
+       } else if (mini_get_debug_options ()->gdb) {
+               mono_xdebug_init ((char*)"gdb");
+               mono_dont_free_domains = TRUE;
+               mono_using_xdebug = TRUE;
        }
 
+#ifdef ENABLE_LLVM
+       mono_llvm_init ();
+#endif
+
        mono_trampolines_init ();
 
        if (!g_thread_supported ())
                g_thread_init (NULL);
 
-       if (getenv ("MONO_DEBUG") != NULL)
-               mini_parse_debug_options ();
-
        mono_gc_base_init ();
 
        mono_jit_tls_id = TlsAlloc ();
@@ -4498,7 +5430,15 @@ mini_init (const char *filename, const char *runtime_version)
        if (default_opt & MONO_OPT_AOT)
                mono_aot_init ();
 
+       mono_debugger_agent_init ();
+
+#ifdef MONO_ARCH_GSHARED_SUPPORTED
+       mono_set_generic_sharing_supported (TRUE);
+#endif
+
+#ifndef MONO_CROSS_COMPILE
        mono_runtime_install_handlers ();
+#endif
        mono_threads_install_cleanup (mini_thread_cleanup);
 
 #ifdef MONO_ARCH_HAVE_NOTIFY_PENDING_EXC
@@ -4515,7 +5455,15 @@ mini_init (const char *filename, const char *runtime_version)
 #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);
@@ -4531,25 +5479,33 @@ mini_init (const char *filename, const char *runtime_version)
        mono_install_get_class_from_name (mono_aot_get_class_from_name);
        mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
 
+       if (debug_options.collect_pagefault_stats) {
+               mono_aot_set_make_unreadable (TRUE);
+       }
+
        if (runtime_version)
                domain = mono_init_version (filename, runtime_version);
        else
                domain = mono_init_from_assembly (filename, filename);
 
        if (mono_aot_only) {
-               /* The IMT tables are very dynamic thus they are hard to AOT */
-               mono_use_imt = FALSE;
                /* This helps catch code allocation requests */
                mono_code_manager_set_read_only (domain->code_mp);
        }
 
 #ifdef MONO_ARCH_HAVE_IMT
        if (mono_use_imt) {
-               mono_install_imt_thunk_builder (mono_arch_build_imt_thunk);
-               mono_install_imt_trampoline (mini_get_imt_trampoline ());
-#if MONO_ARCH_COMMON_VTABLE_TRAMPOLINE
-               mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
-#endif
+               if (mono_aot_only)
+                       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
 
@@ -4591,7 +5547,9 @@ 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);
+#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);
@@ -4751,6 +5709,8 @@ mini_init (const char *filename, const char *runtime_version)
        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_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);
 #endif
 
        mono_generic_sharing_init ();
@@ -4759,6 +5719,10 @@ mini_init (const char *filename, const char *runtime_version)
        mono_simd_intrinsics_init ();
 #endif
 
+#if MONO_SUPPORT_TASKLETS
+       mono_tasklets_init ();
+#endif
+
        if (mono_compile_aot)
                /* 
                 * Avoid running managed code when AOT compiling, since the platform
@@ -4774,7 +5738,7 @@ mini_init (const char *filename, const char *runtime_version)
 #endif
 
        mono_profiler_runtime_initialized ();
-       
+
        MONO_PROBE_VES_INIT_END ();
        
        return domain;
@@ -4875,7 +5839,8 @@ mini_cleanup (MonoDomain *domain)
 #ifndef DISABLE_COM
        cominterop_release_all_rcws ();
 #endif
-       
+
+#ifndef MONO_CROSS_COMPILE     
        /* 
         * mono_runtime_cleanup() and mono_domain_finalize () need to
         * be called early since they need the execution engine still
@@ -4883,14 +5848,17 @@ mini_cleanup (MonoDomain *domain)
         * and mono_runtime_cleanup will wait for other threads to finish).
         */
        mono_domain_finalize (domain, 2000);
+#endif
 
        /* This accesses metadata so needs to be called before runtime shutdown */
        print_jit_stats ();
 
-       mono_runtime_cleanup (domain);
-
        mono_profiler_shutdown ();
 
+#ifndef MONO_CROSS_COMPILE
+       mono_runtime_cleanup (domain);
+#endif
+
        mono_icall_cleanup ();
 
        mono_runtime_cleanup_handlers ();
@@ -4899,6 +5867,10 @@ mini_cleanup (MonoDomain *domain)
 
        mono_debugger_cleanup ();
 
+#ifdef ENABLE_LLVM
+       mono_llvm_cleanup ();
+#endif
+
        mono_trampolines_cleanup ();
 
        mono_unwind_cleanup ();
@@ -4934,6 +5906,12 @@ mono_set_defaults (int verbose_level, guint32 opts)
        default_opt_set = TRUE;
 }
 
+void
+mono_disable_optimizations (guint32 opts)
+{
+       default_opt &= ~opts;
+}
+
 /*
  * mono_get_runtime_build_info:
  *
@@ -4944,9 +5922,9 @@ char*
 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
@@ -5003,3 +5981,12 @@ void mono_precompile_assemblies ()
 
        g_hash_table_destroy (assemblies);
 }
+
+#ifndef DISABLE_JIT
+
+void*
+mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments) {
+       return mono_arch_instrument_epilog_full (cfg, func, p, enable_arguments, FALSE);
+}
+
+#endif