Wed Jun 30 12:10:57 CEST 2010 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / mini.c
index 2458bb6814c1ec9affb45d649ab14887ab8d43ec..3188a2895683b279621c61e7648c58465f971835 100644 (file)
@@ -1,13 +1,15 @@
 /*
  * mini.c: The new Mono code generator.
  *
- * Author:
+ * Authors:
  *   Paolo Molaro (lupus@ximian.com)
  *   Dietmar Maurer (dietmar@ximian.com)
  *
- * (C) 2002 Ximian, Inc.
+ * Copyright 2002-2003 Ximian, Inc.
+ * Coprygith 2003-2010 Novell, Inc.
  */
 
+#define MONO_LLVM_IN_MINI 1
 #include <config.h>
 #include <signal.h>
 #ifdef HAVE_ALLOCA_H
@@ -21,9 +23,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>
 #include <mono/metadata/verify-internals.h>
 #include <mono/metadata/mempool-internals.h>
 #include <mono/metadata/attach.h>
+#include <mono/metadata/runtime.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-counters.h>
-#include <mono/utils/mono-logger.h>
+#include <mono/utils/mono-logger-internal.h>
 #include <mono/utils/mono-mmap.h>
 #include <mono/utils/dtrace.h>
 
 #include "mini.h"
+#include "mini-llvm.h"
 #include "tasklets.h"
 #include <string.h>
 #include <ctype.h>
@@ -74,6 +76,7 @@ static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 op
 MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
 MonoMethodSignature *helper_sig_domain_get = NULL;
 MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
+MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm = NULL;
 MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
 MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL;
 MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL;
@@ -116,14 +119,13 @@ static int methods_with_llvm, methods_without_llvm;
 /*
  * 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.
+ * defaults to FALSE.
  * Changes when this flag is set include:
  * - a per method vtable trampoline is used to handle virtual calls, instead of only
  *   one trampoline.
  * - fast generic virtual calls are not supported.
  */
-#ifdef ENABLE_LLVM
+#if defined(ENABLE_LLVM) && !defined(MONO_LLVM_LOADED)
 gboolean mono_use_llvm = TRUE;
 #else
 gboolean mono_use_llvm = FALSE;
@@ -135,8 +137,7 @@ 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;
 
@@ -163,19 +164,21 @@ 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 {
+       MonoExceptionClause *clause;
+       MonoBasicBlock *basic_block;
+       int start_offset;
+} TryBlockHole;
+
 typedef struct {
        void *ip;
        MonoMethod *method;
@@ -403,6 +406,34 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 {
        return mono_jump_info_token_new2 (mp, image, token, NULL);
 }
+/*
+ * mono_tramp_info_create:
+ *
+ *   Create a MonoTrampInfo structure from the arguments. This function assumes ownership
+ * of NAME, JI, and UNWIND_OPS.
+ */
+MonoTrampInfo*
+mono_tramp_info_create (const char *name, guint8 *code, guint32 code_size, MonoJumpInfo *ji, GSList *unwind_ops)
+{
+       MonoTrampInfo *info = g_new0 (MonoTrampInfo, 1);
+
+       info->name = (char*)name;
+       info->code = code;
+       info->code_size = code_size;
+       info->ji = ji;
+       info->unwind_ops = unwind_ops;
+
+       return info;
+}
+
+void
+mono_tramp_info_free (MonoTrampInfo *info)
+{
+       g_free (info->name);
+
+       // FIXME: ji + unwind_ops
+}
 
 #define MONO_INIT_VARINFO(vi,id) do { \
        (vi)->range.first_use.pos.bid = 0xffff; \
@@ -477,8 +508,7 @@ mono_bblocks_linked (MonoBasicBlock *bb1, MonoBasicBlock *bb2)
 static int
 mono_find_block_region_notry (MonoCompile *cfg, int offset)
 {
-       MonoMethod *method = cfg->method;
-       MonoMethodHeader *header = mono_method_get_header (method);
+       MonoMethodHeader *header = cfg->header;
        MonoExceptionClause *clause;
        int i;
 
@@ -511,7 +541,7 @@ 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);
+               MonoMethodHeader *header = cfg->header;
                
                /*
                 * This can happen if a try clause is nested inside a finally clause.
@@ -655,7 +685,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:
@@ -1223,18 +1255,6 @@ mini_class_is_system_array (MonoClass *klass)
                return FALSE;
 }
 
-static MonoJitICallInfo **emul_opcode_map = NULL;
-
-MonoJitICallInfo *
-mono_find_jit_opcode_emulation (int opcode)
-{
-       g_assert (opcode >= 0 && opcode <= OP_LAST);
-       if  (emul_opcode_map)
-               return emul_opcode_map [opcode];
-       else
-               return NULL;
-}
-
 gboolean
 mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method)
 {
@@ -1283,15 +1303,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 || 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;
                        }
                }
@@ -1301,12 +1325,30 @@ 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)
 {
        helper_sig_domain_get = mono_create_icall_signature ("ptr");
        helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
        helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
+       helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
        helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
        helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
        helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
@@ -1426,6 +1468,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)));
 
@@ -1485,6 +1528,10 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s
                                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:
@@ -1507,6 +1554,8 @@ 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_PTR:
@@ -1517,12 +1566,11 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s
 #else
                case MONO_TYPE_I8:
 #endif
-#ifdef HAVE_SGEN_GC
-                       slot_info = &scalar_stack_slots [MONO_TYPE_I];
-                       break;
-#else
+                       if (cfg->disable_ref_noref_stack_slot_share) {
+                               slot_info = &scalar_stack_slots [MONO_TYPE_I];
+                               break;
+                       }
                        /* Fall through */
-#endif
 
                case MONO_TYPE_CLASS:
                case MONO_TYPE_OBJECT:
@@ -1531,6 +1579,8 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s
                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:
@@ -1650,6 +1700,9 @@ 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
@@ -1717,6 +1770,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);
@@ -1760,6 +1814,10 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
                                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];
@@ -1785,6 +1843,8 @@ 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_PTR:
@@ -1795,12 +1855,11 @@ 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
+                               if (cfg->disable_ref_noref_stack_slot_share) {
+                                       slot_info = &scalar_stack_slots [MONO_TYPE_I];
+                                       break;
+                               }
                                /* Fall through */
-#endif
 
                        case MONO_TYPE_CLASS:
                        case MONO_TYPE_OBJECT:
@@ -1809,6 +1868,8 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
                        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:
@@ -1867,7 +1928,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) {
@@ -1937,21 +1998,50 @@ mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_a
        return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
 }
 
+#define EMUL_HIT_SHIFT 3
+#define EMUL_HIT_MASK ((1 << EMUL_HIT_SHIFT) - 1)
+/* small hit bitmap cache */
+static mono_byte emul_opcode_hit_cache [(OP_LAST>>EMUL_HIT_SHIFT) + 1] = {0};
+static short emul_opcode_num = 0;
+static short emul_opcode_alloced = 0;
+static short *emul_opcode_opcodes = NULL;
+static MonoJitICallInfo **emul_opcode_map = NULL;
+
+MonoJitICallInfo *
+mono_find_jit_opcode_emulation (int opcode)
+{
+       g_assert (opcode >= 0 && opcode <= OP_LAST);
+       if (emul_opcode_hit_cache [opcode >> (EMUL_HIT_SHIFT + 3)] & (1 << (opcode & EMUL_HIT_MASK))) {
+               int i;
+               for (i = 0; i < emul_opcode_num; ++i) {
+                       if (emul_opcode_opcodes [i] == opcode)
+                               return emul_opcode_map [i];
+               }
+       }
+       return NULL;
+}
+
 void
 mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
 {
        MonoJitICallInfo *info;
        MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
 
-       if (!emul_opcode_map)
-               emul_opcode_map = g_new0 (MonoJitICallInfo*, OP_LAST + 1);
-
        g_assert (!sig->hasthis);
        g_assert (sig->param_count < 3);
 
        info = mono_register_jit_icall (func, name, sig, no_throw);
 
-       emul_opcode_map [opcode] = info;
+       if (emul_opcode_num >= emul_opcode_alloced) {
+               int incr = emul_opcode_alloced? emul_opcode_alloced/2: 16;
+               emul_opcode_alloced += incr;
+               emul_opcode_map = g_realloc (emul_opcode_map, sizeof (emul_opcode_map [0]) * emul_opcode_alloced);
+               emul_opcode_opcodes = g_realloc (emul_opcode_opcodes, sizeof (emul_opcode_opcodes [0]) * emul_opcode_alloced);
+       }
+       emul_opcode_map [emul_opcode_num] = info;
+       emul_opcode_opcodes [emul_opcode_num] = opcode;
+       emul_opcode_num++;
+       emul_opcode_hit_cache [opcode >> (EMUL_HIT_SHIFT + 3)] |= (1 << (opcode & EMUL_HIT_MASK));
 }
 
 static void
@@ -2115,6 +2205,10 @@ mono_verify_cfg (MonoCompile *cfg)
 void
 mono_destroy_compile (MonoCompile *cfg)
 {
+       GSList *l;
+
+       if (cfg->header)
+               mono_metadata_free_mh (cfg->header);
        //mono_mempool_stats (cfg->mempool);
        mono_free_loop_info (cfg);
        if (cfg->rs)
@@ -2123,11 +2217,13 @@ mono_destroy_compile (MonoCompile *cfg)
                g_hash_table_destroy (cfg->spvars);
        if (cfg->exvars)
                g_hash_table_destroy (cfg->exvars);
-       mono_mempool_destroy (cfg->mempool);
+       for (l = cfg->headers_to_free; l; l = l->next)
+               mono_metadata_free_mh (l->data);
        g_list_free (cfg->ldstr_list);
        g_hash_table_destroy (cfg->token_info_hash);
        if (cfg->abs_patches)
                g_hash_table_destroy (cfg->abs_patches);
+       mono_mempool_destroy (cfg->mempool);
 
        g_free (cfg->varinfo);
        g_free (cfg->vars);
@@ -2333,7 +2429,7 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
 }
 
 static void
-mono_thread_start_cb (gsize tid, gpointer stack_start, gpointer func)
+mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
 {
        MonoInternalThread *thread;
        void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
@@ -2355,7 +2451,7 @@ mono_thread_abort_dummy (MonoObject *obj)
 }
 
 static void
-mono_thread_attach_cb (gsize tid, gpointer stack_start)
+mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
 {
        MonoInternalThread *thread;
        void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
@@ -2406,18 +2502,19 @@ static MonoInst*
 mono_create_tls_get (MonoCompile *cfg, int offset)
 {
 #ifdef MONO_ARCH_HAVE_TLS_GET
-       MonoInst* ins;
-       
-       if (offset == -1)
-               return NULL;
-       
-       MONO_INST_NEW (cfg, ins, OP_TLS_GET);
-       ins->dreg = mono_alloc_preg (cfg);
-       ins->inst_offset = offset;
-       return ins;
-#else
-       return NULL;
+       if (MONO_ARCH_HAVE_TLS_GET) {
+               MonoInst* ins;
+
+               if (offset == -1)
+                       return NULL;
+
+               MONO_INST_NEW (cfg, ins, OP_TLS_GET);
+               ins->dreg = mono_alloc_preg (cfg);
+               ins->inst_offset = offset;
+               return ins;
+       }
 #endif
+       return NULL;
 }
 
 MonoInst*
@@ -2432,6 +2529,12 @@ mono_get_domain_intrinsic (MonoCompile* cfg)
        return mono_create_tls_get (cfg, mono_domain_get_tls_offset ());
 }
 
+MonoInst*
+mono_get_thread_intrinsic (MonoCompile* cfg)
+{
+       return mono_create_tls_get (cfg, mono_thread_get_tls_offset ());
+}
+
 void
 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
 {
@@ -2686,6 +2789,17 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        case MONO_PATCH_INFO_SFLDA: {
                MonoVTable *vtable = mono_class_vtable (domain, patch_info->data.field->parent);
 
+               if (mono_class_field_is_special_static (patch_info->data.field)) {
+                       gpointer addr = NULL;
+
+                       mono_domain_lock (domain);
+                       if (domain->special_static_fields)
+                               addr = g_hash_table_lookup (domain->special_static_fields, patch_info->data.field);
+                       mono_domain_unlock (domain);
+                       g_assert (addr);
+                       return addr;
+               }
+
                g_assert (vtable);
                if (!vtable->initialized && !(vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && (method && mono_class_needs_cctor_run (vtable->klass, method)))
                        /* Done by the generated code */
@@ -2841,6 +2955,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)
 {
@@ -2848,7 +2973,7 @@ mono_compile_create_vars (MonoCompile *cfg)
        MonoMethodHeader *header;
        int i;
 
-       header = mono_method_get_header (cfg->method);
+       header = cfg->header;
 
        sig = mono_method_signature (cfg->method);
        
@@ -2901,6 +3026,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)
 {
@@ -3006,6 +3133,117 @@ mono_postprocess_patches (MonoCompile *cfg)
        }
 }
 
+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)
 {
@@ -3048,6 +3286,7 @@ mono_codegen (MonoCompile *cfg)
                bb->native_offset = cfg->code_len;
                //if ((bb == cfg->bb_entry) || !(bb->region == -1 && !bb->dfn))
                        mono_arch_output_basic_block (cfg, bb);
+               bb->native_length = cfg->code_len - bb->native_offset;
 
                if (bb == cfg->bb_exit) {
                        cfg->epilog_begin = cfg->code_len;
@@ -3164,137 +3403,428 @@ compute_reachable (MonoBasicBlock *bb)
        }
 }
 
-/*
- * mini_method_compile:
- * @method: the method to compile
- * @opts: the optimization flags to use
- * @domain: the domain where the method will be compiled in
- * @run_cctors: whether we should run type ctors if possible
- * @compile_aot: whether this is an AOT compilation
- * @parts: debug flag
- *
- * Returns: a MonoCompile* pointer. Caller must check the exception_type
- * field in the returned struct to see if compilation succeded.
- */
-MonoCompile*
-mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
+static MonoJitInfo*
+create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
 {
+       GSList *tmp;
        MonoMethodHeader *header;
-       guint8 *ip;
-       MonoCompile *cfg;
        MonoJitInfo *jinfo;
-       int dfn, i, code_size_ratio;
-       gboolean deadce_has_run = FALSE;
-       gboolean try_generic_shared, try_llvm;
-       MonoMethod *method_to_compile, *method_to_register;
+       int num_clauses;
        int generic_info_size;
+       int holes_size = 0, num_holes = 0;
 
-       mono_jit_stats.methods_compiled++;
-       if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
-               mono_profiler_method_jit (method);
-       if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ())
-               MONO_PROBE_METHOD_COMPILE_BEGIN (method);
-       if (compile_aot)
-               /* We are passed the original generic method definition */
-               try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
-                       (opts & MONO_OPT_GSHARED) && (method->is_generic || method->klass->generic_container);
-       else
-               try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
-                       (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method, FALSE);
-
-       if (opts & MONO_OPT_GSHARED) {
-               if (try_generic_shared)
-                       mono_stats.generics_sharable_methods++;
-               else if (mono_method_is_generic_impl (method))
-                       mono_stats.generics_unsharable_methods++;
-       }
-
-       try_llvm = TRUE;
-
-#ifndef ENABLE_LLVM
-       try_llvm = FALSE;
-#endif
+       g_assert (method_to_compile == cfg->method);
+       header = cfg->header;
 
- restart_compile:
-       if (try_generic_shared) {
-               MonoMethod *declaring_method;
-               MonoGenericContext *shared_context;
+       if (cfg->generic_sharing_context)
+               generic_info_size = sizeof (MonoGenericJitInfo);
+       else
+               generic_info_size = 0;
 
-               if (compile_aot) {
-                       declaring_method = method;
-               } else {
-                       declaring_method = mono_method_get_declaring_generic_method (method);
-                       if (method->klass->generic_class)
-                               g_assert (method->klass->generic_class->container_class == declaring_method->klass);
-                       else
-                               g_assert (method->klass == declaring_method->klass);
+       if (cfg->try_block_holes) {
+               for (tmp = cfg->try_block_holes; tmp; tmp = tmp->next) {
+                       TryBlockHole *hole = tmp->data;
+                       MonoExceptionClause *ec = hole->clause;
+                       int hole_end = hole->basic_block->native_offset + hole->basic_block->native_length;
+                       MonoBasicBlock *clause_last_bb = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
+                       g_assert (clause_last_bb);
+
+                       /* Holes at the end of a try region can be represented by simply reducing the size of the block itself.*/
+                       if (clause_last_bb->native_offset != hole_end)
+                               ++num_holes;
                }
+               if (num_holes)
+                       holes_size = sizeof (MonoTryBlockHoleTableJitInfo) + num_holes * sizeof (MonoTryBlockHoleJitInfo);
+               if (G_UNLIKELY (cfg->verbose_level >= 4))
+                       printf ("Number of try block holes %d\n", num_holes);
+       }
 
-               if (declaring_method->is_generic)
-                       shared_context = &(mono_method_get_generic_container (declaring_method)->context);
-               else
-                       shared_context = &declaring_method->klass->generic_container->context;
+       if (COMPILE_LLVM (cfg))
+               num_clauses = cfg->llvm_ex_info_len;
+       else
+               num_clauses = header->num_clauses;
 
-               method_to_compile = mono_class_inflate_generic_method (declaring_method, shared_context);
-               g_assert (method_to_compile);
+       if (cfg->method->dynamic) {
+               jinfo = g_malloc0 (MONO_SIZEOF_JIT_INFO + (num_clauses * sizeof (MonoJitExceptionInfo)) +
+                               generic_info_size + holes_size);
        } else {
-               method_to_compile = method;
+               jinfo = mono_domain_alloc0 (cfg->domain, MONO_SIZEOF_JIT_INFO +
+                               (num_clauses * sizeof (MonoJitExceptionInfo)) +
+                               generic_info_size + holes_size);
        }
 
-       cfg = g_new0 (MonoCompile, 1);
-       cfg->method = method_to_compile;
-       cfg->mempool = mono_mempool_new ();
-       cfg->opt = opts;
-       cfg->prof_options = mono_profiler_get_events ();
-       cfg->run_cctors = run_cctors;
-       cfg->domain = domain;
-       cfg->verbose_level = mini_verbose;
-       cfg->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->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container)) {
-               cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;
-               return cfg;
-       }
+       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) {
-               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;
+               MonoInst *inst;
+               MonoGenericJitInfo *gi;
 
-       /* No way to obtain the location info for 'this' */
-       if (try_generic_shared) {
-               cfg->exception_message = g_strdup ("gshared");
-               cfg->disable_llvm = TRUE;
-       }
+               jinfo->has_generic_jit_info = 1;
 
-       if (cfg->method->save_lmf) {
-               cfg->exception_message = g_strdup ("lmf");
-               cfg->disable_llvm = TRUE;
-       }
+               gi = mono_jit_info_get_generic_jit_info (jinfo);
+               g_assert (gi);
 
-       /* FIXME: */
-       if (cfg->method->dynamic) {
-               cfg->exception_message = g_strdup ("dynamic.");
-               cfg->disable_llvm = TRUE;
-       }
+               gi->generic_sharing_context = cfg->generic_sharing_context;
 
-       header = mono_method_get_header (method_to_compile);
-       if (!header) {
-               MonoLoaderError *error;
+               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;
+                       if (!COMPILE_LLVM (cfg))
+                               g_assert (inst->opcode == OP_REGOFFSET);
+               } else {
+                       inst = cfg->args [0];
+               }
+
+               if (COMPILE_LLVM (cfg)) {
+                       g_assert (cfg->llvm_this_reg != -1);
+                       gi->this_in_reg = 0;
+                       gi->this_reg = cfg->llvm_this_reg;
+                       gi->this_offset = cfg->llvm_this_offset;
+               } else if (inst->opcode == OP_REGVAR) {
+                       gi->this_in_reg = 1;
+                       gi->this_reg = inst->dreg;
+               } else {
+                       g_assert (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 (num_holes) {
+               MonoTryBlockHoleTableJitInfo *table;
+               int i;
+
+               jinfo->has_try_block_holes = 1;
+               table = mono_jit_info_get_try_block_hole_table_info (jinfo);
+               table->num_holes = (guint16)num_holes;
+               i = 0;
+               for (tmp = cfg->try_block_holes; tmp; tmp = tmp->next) {
+                       guint32 start_bb_offset;
+                       MonoTryBlockHoleJitInfo *hole;
+                       TryBlockHole *hole_data = tmp->data;
+                       MonoExceptionClause *ec = hole_data->clause;
+                       int hole_end = hole_data->basic_block->native_offset + hole_data->basic_block->native_length;
+                       MonoBasicBlock *clause_last_bb = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
+                       g_assert (clause_last_bb);
+
+                       /* Holes at the end of a try region can be represented by simply reducing the size of the block itself.*/
+                       if (clause_last_bb->native_offset == hole_end)
+                               continue;
+
+                       start_bb_offset = hole_data->start_offset - hole_data->basic_block->native_offset;
+                       hole = &table->holes [i++];
+                       hole->clause = hole_data->clause - &header->clauses [0];
+                       hole->offset = (guint32)hole_data->start_offset;
+                       hole->length = (guint16)(hole_data->basic_block->native_length - start_bb_offset);
+
+                       if (G_UNLIKELY (cfg->verbose_level >= 4))
+                               printf ("\tTry block hole at eh clause %d offset %x length %x\n", hole->clause, hole->offset, hole->length);
+               }
+               g_assert (i == num_holes);
+       }
+
+       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;
+
+                       for (tmp = cfg->try_block_holes; tmp; tmp = tmp->next) {
+                               TryBlockHole *hole = tmp->data;
+                               gpointer hole_end = cfg->native_code + (hole->basic_block->native_offset + hole->basic_block->native_length);
+                               if (hole->clause == ec && hole_end == ei->try_end) {
+                                       if (G_UNLIKELY (cfg->verbose_level >= 4))
+                                               printf ("\tShortening try block %d from %x to %x\n", i, (int)((guint8*)ei->try_end - cfg->native_code), hole->start_offset);
+
+                                       ei->try_end = cfg->native_code + hole->start_offset;
+                                       break;
+                               }
+                       }
+
+                       if (ec->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
+                               int end_offset;
+                               if (ec->handler_offset + ec->handler_len < header->code_size) {
+                                       tblock = cfg->cil_offset_to_bb [ec->handler_offset + ec->handler_len];
+                                       g_assert (tblock);
+                                       end_offset = tblock->native_offset;
+                               } else {
+                                       end_offset = cfg->epilog_begin;
+                               }
+                               ei->data.handler_end = cfg->native_code + end_offset;
+                       }
+               }
+       }
+
+       if (G_UNLIKELY (cfg->verbose_level >= 4)) {
+               int i;
+               for (i = 0; i < jinfo->num_clauses; i++) {
+                       MonoJitExceptionInfo *ei = &jinfo->clauses [i];
+                       int start = (guint8*)ei->try_start - cfg->native_code;
+                       int end = (guint8*)ei->try_end - cfg->native_code;
+                       int handler = (guint8*)ei->handler_start - cfg->native_code;
+
+                       printf ("JitInfo EH clause %d flags %x try %x-%x handler %x\n", i, ei->flags, start, end, handler);
+               }
+       }
+
+       /* 
+        * 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;
+}
+#endif
+
+/*
+ * mini_get_shared_method:
+ *
+ *   Return the method which is actually compiled/registered when doing generic sharing.
+ */
+MonoMethod*
+mini_get_shared_method (MonoMethod *method)
+{
+       MonoGenericContext shared_context;
+       MonoMethod *declaring_method, *res;
+       int i;
+       gboolean partial = FALSE;
+
+       if (method->is_generic || method->klass->generic_container)
+               declaring_method = method;
+       else
+               declaring_method = mono_method_get_declaring_generic_method (method);
+
+       if (declaring_method->is_generic)
+               shared_context = mono_method_get_generic_container (declaring_method)->context;
+       else
+               shared_context = declaring_method->klass->generic_container->context;
+
+       /* Handle partial sharing */
+       if (method != declaring_method && method->is_inflated && !mono_method_is_generic_sharable_impl_full (method, FALSE, FALSE)) {
+               MonoGenericContext *context = mono_method_get_context (method);
+               MonoGenericInst *inst;
+               MonoType **type_argv;
+
+               /* 
+                * Create the shared context by replacing the ref type arguments with
+                * type parameters, and keeping the rest.
+                */
+               partial = TRUE;
+               inst = context->class_inst;
+               if (inst) {
+                       type_argv = g_new0 (MonoType*, inst->type_argc);
+                       for (i = 0; i < inst->type_argc; ++i) {
+                               if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                       type_argv [i] = shared_context.class_inst->type_argv [i];
+                               else
+                                       type_argv [i] = inst->type_argv [i];
+                       }
+
+                       shared_context.class_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+                       g_free (type_argv);
+               }
+
+               inst = context->method_inst;
+               if (inst) {
+                       type_argv = g_new0 (MonoType*, inst->type_argc);
+                       for (i = 0; i < inst->type_argc; ++i) {
+                               if (MONO_TYPE_IS_REFERENCE (inst->type_argv [i]) || inst->type_argv [i]->type == MONO_TYPE_VAR || inst->type_argv [i]->type == MONO_TYPE_MVAR)
+                                       type_argv [i] = shared_context.method_inst->type_argv [i];
+                               else
+                                       type_argv [i] = inst->type_argv [i];
+                       }
+
+                       shared_context.method_inst = mono_metadata_get_generic_inst (inst->type_argc, type_argv);
+                       g_free (type_argv);
+               }
+       }
+
+    res = mono_class_inflate_generic_method (declaring_method, &shared_context);
+       if (!partial) {
+               /* The result should be an inflated method whose parent is not inflated */
+               g_assert (!res->klass->is_inflated);
+       }
+       return res;
+}
+
+#ifndef DISABLE_JIT
+/*
+ * mini_method_compile:
+ * @method: the method to compile
+ * @opts: the optimization flags to use
+ * @domain: the domain where the method will be compiled in
+ * @run_cctors: whether we should run type ctors if possible
+ * @compile_aot: whether this is an AOT compilation
+ * @parts: debug flag
+ *
+ * Returns: a MonoCompile* pointer. Caller must check the exception_type
+ * field in the returned struct to see if compilation succeded.
+ */
+MonoCompile*
+mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
+{
+       MonoMethodHeader *header;
+       MonoMethodSignature *sig;
+       MonoError err;
+       guint8 *ip;
+       MonoCompile *cfg;
+       int dfn, i, code_size_ratio;
+       gboolean deadce_has_run = FALSE;
+       gboolean try_generic_shared, try_llvm;
+       MonoMethod *method_to_compile, *method_to_register;
+
+       mono_jit_stats.methods_compiled++;
+       if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
+               mono_profiler_method_jit (method);
+       if (MONO_PROBE_METHOD_COMPILE_BEGIN_ENABLED ())
+               MONO_PROBE_METHOD_COMPILE_BEGIN (method);
+       if (compile_aot)
+               /* 
+                * We might get passed the original generic method definition or
+                * instances with type parameters.
+                * FIXME: Remove the method->klass->generic_class limitation.
+                */
+               try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
+                       (opts & MONO_OPT_GSHARED) && ((method->is_generic || method->klass->generic_container) || (!method->klass->generic_class && mono_method_is_generic_sharable_impl (method, TRUE)));
+       else
+               try_generic_shared = mono_class_generic_sharing_enabled (method->klass) &&
+                       (opts & MONO_OPT_GSHARED) && mono_method_is_generic_sharable_impl (method, FALSE);
+
+       if (opts & MONO_OPT_GSHARED) {
+               if (try_generic_shared)
+                       mono_stats.generics_sharable_methods++;
+               else if (mono_method_is_generic_impl (method))
+                       mono_stats.generics_unsharable_methods++;
+       }
+
+       try_llvm = mono_use_llvm;
+
+ restart_compile:
+       if (try_generic_shared) {
+               method_to_compile = mini_get_shared_method (method);
+               g_assert (method_to_compile);
+       } else {
+               method_to_compile = method;
+       }
+
+       cfg = g_new0 (MonoCompile, 1);
+       cfg->method = method_to_compile;
+       cfg->header = mono_method_get_header (cfg->method);
+       cfg->mempool = mono_mempool_new ();
+       cfg->opt = opts;
+       cfg->prof_options = mono_profiler_get_events ();
+       cfg->run_cctors = run_cctors;
+       cfg->domain = domain;
+       cfg->verbose_level = mini_verbose;
+       cfg->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) {
+               method_to_register = method_to_compile;
+       } else {
+               g_assert (method == method_to_compile);
+               method_to_register = method;
+       }
+       cfg->method_to_register = method_to_register;
+
+       mono_error_init (&err);
+       sig = mono_method_signature_checked (cfg->method, &err);        
+       if (!sig) {
+               cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
+               cfg->exception_message = g_strdup (mono_error_get_message (&err));
+               mono_error_cleanup (&err);
+               if (MONO_PROBE_METHOD_COMPILE_END_ENABLED ())
+                       MONO_PROBE_METHOD_COMPILE_END (method, FALSE);
+               return cfg;
+       }
+
+       header = cfg->header;
+       if (!header) {
+               MonoLoaderError *error;
 
                if ((error = mono_loader_get_last_error ())) {
                        cfg->exception_type = error->exception_type;
@@ -3307,16 +3837,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                return cfg;
        }
 
-       if (header->clauses) {
-               /* 
-                * Cannot be enabled until LLVM supports implicit exceptions, or we use
-                * explicit checks, or we disable this for methods which might throw implicit
-                * exceptions inside clauses.
-                */
-               cfg->exception_message = g_strdup ("clauses");
-               cfg->disable_llvm = TRUE;
-       }
-
 #ifdef ENABLE_LLVM
        {
                static gboolean inited;
@@ -3326,21 +3846,24 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                        mono_counters_register ("Methods JITted using mono JIT", MONO_COUNTER_JIT | MONO_COUNTER_INT, &methods_without_llvm);
                        inited = TRUE;
                }
-       
+
                /* 
                 * Check for methods which cannot be compiled by LLVM early, to avoid
                 * the extra compilation pass.
                 */
-               if (COMPILE_LLVM (cfg) && cfg->disable_llvm) {
-                       if (cfg->verbose_level >= 1) {
-                               //nm = mono_method_full_name (cfg->method, TRUE);
-                               printf ("LLVM failed for '%s': %s\n", method->name, cfg->exception_message);
-                               //g_free (nm);
+               if (COMPILE_LLVM (cfg)) {
+                       mono_llvm_check_method_supported (cfg);
+                       if (cfg->disable_llvm) {
+                               if (cfg->verbose_level >= 1) {
+                                       //nm = mono_method_full_name (cfg->method, TRUE);
+                                       printf ("LLVM failed for '%s': %s\n", method->name, cfg->exception_message);
+                                       //g_free (nm);
+                               }
+                               InterlockedIncrement (&methods_without_llvm);
+                               mono_destroy_compile (cfg);
+                               try_llvm = FALSE;
+                               goto restart_compile;
                        }
-                       InterlockedIncrement (&methods_without_llvm);
-                       mono_destroy_compile (cfg);
-                       try_llvm = FALSE;
-                       goto restart_compile;
                }
        }
 #endif
@@ -3374,6 +3897,9 @@ 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;
        }
 
        if (mono_using_xdebug) {
@@ -3385,15 +3911,30 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                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_cfg (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, '.') > 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;
@@ -3404,7 +3945,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                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));
+                       g_print ("converting shared method %s\n", mono_method_full_name (method_to_compile, TRUE));
                else
                        g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
        }
@@ -3474,6 +4015,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
         */
@@ -3737,7 +4282,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                mono_decompose_array_access_opts (cfg);
 
        if (cfg->got_var) {
+#ifndef MONO_ARCH_GOT_REG
                GList *regs;
+#endif
+               int got_reg;
 
                g_assert (cfg->got_var_allocated);
 
@@ -3748,13 +4296,17 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                 * branches problem. Testcase: mcs crash in 
                 * System.MonoCustomAttrs:GetCustomAttributes.
                 */
+#ifdef MONO_ARCH_GOT_REG
+               got_reg = MONO_ARCH_GOT_REG;
+#else
                regs = mono_arch_get_global_int_regs (cfg);
                g_assert (regs);
+               got_reg = GPOINTER_TO_INT (regs->data);
+               g_list_free (regs);
+#endif
                cfg->got_var->opcode = OP_REGVAR;
-               cfg->got_var->dreg = GPOINTER_TO_INT (regs->data);
+               cfg->got_var->dreg = got_reg;
                cfg->used_int_regs |= 1LL << cfg->got_var->dreg;
-               
-               g_list_free (regs);
        }
 
        /*
@@ -3773,7 +4325,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
 
        if ((cfg->opt & MONO_OPT_LINEARS) && !cfg->globalra) {
-               GList *vars, *regs;
+               GList *vars, *regs, *l;
                
                /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
                cfg->comp_done &= ~MONO_COMP_LIVENESS;
@@ -3782,8 +4334,15 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
                if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
                        regs = mono_arch_get_global_int_regs (cfg);
-                       if (cfg->got_var)
-                               regs = g_list_delete_link (regs, regs);
+                       /* Remove the reg reserved for holding the GOT address */
+                       if (cfg->got_var) {
+                               for (l = regs; l; l = l->next) {
+                                       if (GPOINTER_TO_UINT (l->data) == cfg->got_var->dreg) {
+                                               regs = g_list_delete_link (regs, l);
+                                               break;
+                                       }
+                               }
+                       }
                        mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
                }
        }
@@ -3869,10 +4428,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
                if (!cfg->disable_llvm)
                        mono_llvm_emit_method (cfg);
-               if (!cfg->disable_llvm && header->num_clauses && !cfg->compile_aot && cfg->llvm_ex_info_len != header->num_clauses) {
-                       cfg->exception_message = g_strdup ("clause num mismatch.");
-                       cfg->disable_llvm = TRUE;
-               }
                if (cfg->disable_llvm) {
                        if (cfg->verbose_level >= 1) {
                                //nm = mono_method_full_name (cfg->method, TRUE);
@@ -3905,139 +4460,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                g_free (id);
        }
 
-       if (cfg->generic_sharing_context)
-               generic_info_size = sizeof (MonoGenericJitInfo);
-       else
-               generic_info_size = 0;
-
-       if (cfg->method->dynamic) {
-               jinfo = g_malloc0 (MONO_SIZEOF_JIT_INFO + (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
-                               generic_info_size);
-       } else {
-               jinfo = mono_domain_alloc0 (cfg->domain, MONO_SIZEOF_JIT_INFO +
-                               (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
-                               generic_info_size);
-       }
-
-       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 (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 (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;
-                       }
-
-                       if (COMPILE_LLVM (cfg)) {
-                               if (!cfg->compile_aot) {
-                                       g_assert (cfg->llvm_ex_info && i < cfg->llvm_ex_info_len);
-                                       ei->try_start = cfg->llvm_ex_info [i].try_start;
-                                       ei->try_end = cfg->llvm_ex_info [i].try_end;
-                                       ei->handler_start = cfg->llvm_ex_info [i].handler_start;
-                               }
-                       } else {
-                               tblock = cfg->cil_offset_to_bb [ec->try_offset];
-                               g_assert (tblock);
-                               ei->try_start = cfg->native_code + tblock->native_offset;
-                               g_assert (tblock->native_offset);
-                               tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
-                               g_assert (tblock);
-                               ei->try_end = cfg->native_code + tblock->native_offset;
-                               g_assert (tblock->native_offset);
-                               tblock = cfg->cil_offset_to_bb [ec->handler_offset];
-                               g_assert (tblock);
-                               ei->handler_start = cfg->native_code + tblock->native_offset;
-                       }
-               }
-       }
-
-       /* 
-        * 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
-
-       cfg->jit_info = jinfo;
+       cfg->jit_info = create_jit_info (cfg, method_to_compile);
 
 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
        if (cfg->extend_live_ranges) {
@@ -4051,19 +4474,14 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        mini_gc_create_gc_map (cfg);
  
-       if (cfg->seq_points) {
-               // FIXME: dynamic methods
-               mono_domain_lock (domain);
-               g_hash_table_insert (domain_jit_info (domain)->seq_points, method_to_register, cfg->seq_points);
-               mono_domain_unlock (domain);
-       }
+       mono_save_seq_point_info (cfg);
 
        if (!cfg->compile_aot) {
                mono_domain_lock (cfg->domain);
-               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);
        }
 
@@ -4077,7 +4495,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                g_free (mono_jit_stats.biggest_method);
                mono_jit_stats.biggest_method = g_strdup_printf ("%s::%s)", method->klass->name, method->name);
        }
-       code_size_ratio = (code_size_ratio * 100) / mono_method_get_header (method)->code_size;
+       code_size_ratio = (code_size_ratio * 100) / header->code_size;
        if (code_size_ratio > mono_jit_stats.max_code_size_ratio && mono_jit_stats.enabled) {
                mono_jit_stats.max_code_size_ratio = code_size_ratio;
                g_free (mono_jit_stats.max_ratio_method);
@@ -4102,17 +4520,29 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
 #endif /* DISABLE_JIT */
 
-static MonoJitInfo*
-lookup_generic_method (MonoDomain *domain, MonoMethod *method)
+MonoJitInfo*
+mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *method)
 {
-       MonoMethod *open_method;
+       static gboolean inited = FALSE;
+       static int lookups = 0;
+       static int failed_lookups = 0;
+       MonoJitInfo *ji;
 
-       if (!mono_method_is_generic_sharable_impl (method, FALSE))
-               return NULL;
+       ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, mini_get_shared_method (method));
+       if (ji && !ji->has_generic_jit_info)
+               ji = NULL;
 
-       open_method = mono_method_get_declaring_generic_method (method);
+       if (!inited) {
+               mono_counters_register ("Shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &lookups);
+               mono_counters_register ("Failed shared generic lookups", MONO_COUNTER_INT|MONO_COUNTER_GENERICS, &failed_lookups);
+               inited = TRUE;
+       }
+
+       ++lookups;
+       if (!ji)
+               ++failed_lookups;
 
-       return mono_domain_lookup_shared_generic (domain, open_method);
+       return ji;
 }
 
 /*
@@ -4126,7 +4556,9 @@ lookup_method_inner (MonoDomain *domain, MonoMethod *method)
        if (ji)
                return ji;
 
-       return lookup_generic_method (domain, method);
+       if (!mono_method_is_generic_sharable_impl (method, FALSE))
+               return NULL;
+       return mono_domain_lookup_shared_generic (domain, method);
 }
 
 static MonoJitInfo*
@@ -4143,6 +4575,38 @@ lookup_method (MonoDomain *domain, MonoMethod *method)
        return info;
 }
 
+#if ENABLE_JIT_MAP
+static FILE* perf_map_file = NULL;
+
+void
+mono_enable_jit_map (void)
+{
+       if (!perf_map_file) {
+               char name [64];
+               g_snprintf (name, sizeof (name), "/tmp/perf-%d.map", getpid ());
+               unlink (name);
+               perf_map_file = fopen (name, "w");
+       }
+}
+
+void
+mono_emit_jit_tramp (void *start, int size, const char *desc)
+{
+       if (perf_map_file)
+               fprintf (perf_map_file, "%llx %x %s\n", (long long unsigned int)(gsize)start, size, desc);
+}
+
+void
+mono_emit_jit_map (MonoJitInfo *jinfo)
+{
+       if (perf_map_file) {
+               char *name = mono_method_full_name (jinfo->method, TRUE);
+               mono_emit_jit_tramp (jinfo->code_start, jinfo->code_size, name);
+               g_free (name);
+       }
+}
+#endif
+
 static gpointer
 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt, MonoException **jit_ex)
 {
@@ -4311,12 +4775,12 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        }
 
        if (ex) {
-               mono_destroy_compile (cfg);
-               *jit_ex = 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;
        }
 
@@ -4354,6 +4818,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
        mono_destroy_compile (cfg);
 
+#ifndef DISABLE_JIT
        if (domain_jit_info (target_domain)->jump_target_hash) {
                MonoJumpInfo patch_info;
                GSList *list, *tmp;
@@ -4370,21 +4835,36 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                g_slist_free (list);
        }
 
+       mono_emit_jit_map (jinfo);
+#endif
        mono_domain_unlock (target_domain);
        mono_loader_unlock ();
 
        vtable = mono_class_vtable (target_domain, method->klass);
        if (!vtable) {
-               MonoException *exc;
-               exc = mono_class_get_exception_for_failure (method->klass);
-               g_assert (exc);
-               mono_raise_exception (exc);
+               ex = mono_class_get_exception_for_failure (method->klass);
+               g_assert (ex);
+               *jit_ex = ex;
+               return NULL;
        }
 
-       if (prof_options & MONO_PROFILE_JIT_COMPILATION)
-               mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
+       if (prof_options & MONO_PROFILE_JIT_COMPILATION) {
+               if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
+                       if (mono_marshal_method_from_wrapper (method)) {
+                               /* Native func wrappers have no method */
+                               /* The profiler doesn't know about wrappers, so pass the original icall method */
+                               mono_profiler_method_end_jit (mono_marshal_method_from_wrapper (method), jinfo, MONO_PROFILE_OK);
+                       }
+               } else {
+                       mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
+               }
+       }
 
-       mono_runtime_class_init (vtable);
+       ex = mono_runtime_class_init_full (vtable, FALSE);
+       if (ex) {
+               *jit_ex = ex;
+               return NULL;
+       }
        return code;
 }
 
@@ -4736,7 +5216,17 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
         * We need this here because mono_marshal_get_runtime_invoke can place 
         * the helper method in System.Object and not the target class.
         */
-       mono_runtime_class_init (info->vtable);
+       if (exc) {
+               *exc = (MonoObject*)mono_runtime_class_init_full (info->vtable, FALSE);
+               if (*exc)
+                       return NULL;
+       } else {
+               mono_runtime_class_init (info->vtable);
+       }
+
+       /* The wrappers expect this to be initialized to NULL */
+       if (exc)
+               *exc = NULL;
 
 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
        if (info->dyn_call_info) {
@@ -4829,18 +5319,19 @@ SIG_HANDLER_SIGNATURE (mono_sigill_signal_handler)
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
+#if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
+#define HAVE_SIG_INFO
+#endif
+
 void
 SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler)
 {
-#ifndef MONO_ARCH_SIGSEGV_ON_ALTSTACK
-       MonoException *exc = NULL;
-#endif
        MonoJitInfo *ji;
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
 
        GET_CONTEXT;
 
-#ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
+#if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED) && defined(HAVE_SIG_INFO)
        if (mono_arch_is_single_step_event (info, ctx)) {
                mono_debugger_agent_single_step_event (ctx);
                return;
@@ -4850,6 +5341,13 @@ SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler)
        }
 #endif
 
+#if !defined(HOST_WIN32) && defined(HAVE_SIG_INFO)
+       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))
@@ -4893,7 +5391,7 @@ SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler)
                mono_handle_native_sigsegv (SIGSEGV, ctx);
        }
                        
-       mono_arch_handle_exception (ctx, exc, FALSE);
+       mono_arch_handle_exception (ctx, NULL, FALSE);
 #endif
 }
 
@@ -4923,7 +5421,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);
        }
 
@@ -4937,24 +5435,44 @@ mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, Mon
        return mono_get_addr_from_ftnptr (addr);
 }
 
-#ifdef MONO_ARCH_HAVE_IMT
-static G_GNUC_UNUSED gpointer
-mini_get_imt_trampoline (void)
+static gpointer *vtable_trampolines;
+static int vtable_trampolines_size;
+
+gpointer
+mini_get_vtable_trampoline (int slot_index)
 {
-       static gpointer tramp = NULL;
-       if (!tramp)
-               tramp = mono_create_specific_trampoline (MONO_FAKE_IMT_METHOD, MONO_TRAMPOLINE_JIT, mono_get_root_domain (), NULL);
-       return tramp;
+       int index = slot_index + MONO_IMT_SIZE;
+
+       g_assert (slot_index >= - MONO_IMT_SIZE);
+       if (!vtable_trampolines || slot_index + MONO_IMT_SIZE >= vtable_trampolines_size) {
+               mono_jit_lock ();
+               if (!vtable_trampolines || index >= vtable_trampolines_size) {
+                       int new_size;
+                       gpointer new_table;
+
+                       new_size = vtable_trampolines_size ? vtable_trampolines_size * 2 : 128;
+                       while (new_size <= index)
+                               new_size *= 2;
+                       new_table = g_new0 (gpointer, new_size);
+
+                       if (vtable_trampolines)
+                               memcpy (new_table, vtable_trampolines, vtable_trampolines_size * sizeof (gpointer));
+                       mono_memory_barrier ();
+                       vtable_trampolines = new_table;
+                       vtable_trampolines_size = new_size;
+               }
+               mono_jit_unlock ();
+       }
+
+       if (!vtable_trampolines [index])
+               vtable_trampolines [index] = mono_create_specific_trampoline (GUINT_TO_POINTER (slot_index), MONO_TRAMPOLINE_VCALL, mono_get_root_domain (), NULL);
+       return vtable_trampolines [index];
 }
-#endif
 
-gpointer
-mini_get_vtable_trampoline (void)
+static gpointer
+mini_get_imt_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;
+       return mini_get_vtable_trampoline (slot_index - MONO_IMT_SIZE);
 }
 
 static void
@@ -4991,9 +5509,13 @@ mini_parse_debug_options (void)
                        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', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks'\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);
                }
        }
@@ -5057,7 +5579,7 @@ mini_create_jit_domain_info (MonoDomain *domain)
        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 (mono_aligned_addr_hash, NULL);
+       info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, g_free);
        info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
 
        domain->runtime_info = info;
@@ -5116,6 +5638,8 @@ mini_free_jit_domain_info (MonoDomain *domain)
                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);
@@ -5151,7 +5675,7 @@ mini_init (const char *filename, const char *runtime_version)
 #endif
 
 #ifdef MONO_ARCH_HAVE_TLS_GET
-       mono_runtime_set_has_tls_get (TRUE);
+       mono_runtime_set_has_tls_get (MONO_ARCH_HAVE_TLS_GET);
 #else
        mono_runtime_set_has_tls_get (FALSE);
 #endif
@@ -5165,6 +5689,13 @@ mini_init (const char *filename, const char *runtime_version)
        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) {
+               callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
+               callbacks.get_imt_trampoline = mini_get_imt_trampoline;
+       }
+#endif
+
        mono_install_callbacks (&callbacks);
        
        mono_arch_cpu_init ();
@@ -5191,7 +5722,12 @@ mini_init (const char *filename, const char *runtime_version)
        }
 
 #ifdef ENABLE_LLVM
-       mono_llvm_init ();
+       if (!mono_llvm_load (NULL)) {
+               mono_use_llvm = FALSE;
+               fprintf (stderr, "Mono Warning: llvm support could not be loaded.\n");
+       }
+       if (mono_use_llvm)
+               mono_llvm_init ();
 #endif
 
        mono_trampolines_init ();
@@ -5199,8 +5735,6 @@ mini_init (const char *filename, const char *runtime_version)
        if (!g_thread_supported ())
                g_thread_init (NULL);
 
-       mono_gc_base_init ();
-
        mono_jit_tls_id = TlsAlloc ();
        setup_jit_tls_data ((gpointer)-1, mono_thread_abort);
 
@@ -5232,15 +5766,7 @@ 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);
@@ -5256,6 +5782,10 @@ 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
@@ -5272,15 +5802,6 @@ mini_init (const char *filename, const char *runtime_version)
                        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) {
-                       /* LLVM needs a per-method vtable trampoline */
-                       mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
-                       /* 
-                        * The imt code in mono_magic_trampoline () can't handle LLVM code. By disabling
-                        * this, we force iface calls to go through the llvm vcall trampoline.
-                        */
-                       mono_install_imt_trampoline (mini_get_imt_trampoline ());
-               }
        }
 #endif
 
@@ -5322,7 +5843,6 @@ 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);
-       register_icall (mono_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", "void ptr", TRUE); 
 #if MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION
        register_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", 
                                 "void ptr", TRUE);
@@ -5448,6 +5968,10 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
 #endif
 
+#ifdef COMPRESSED_INTERFACE_BITMAP
+       register_icall (mono_class_interface_match, "mono_class_interface_match", "uint32 ptr int32", TRUE);
+#endif
+
 #if SIZEOF_REGISTER == 4
        mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
 #endif
@@ -5482,6 +6006,14 @@ 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);
+       register_icall (mono_resume_unwind, "mono_resume_unwind", "void", TRUE);
+
+#ifdef HAVE_WRITE_BARRIERS
+       register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);
+#endif
+
 #endif
 
        mono_generic_sharing_init ();
@@ -5578,13 +6110,9 @@ print_jit_stats (void)
                g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
 
                g_print ("Hazardous pointers:     %ld\n", mono_stats.hazardous_pointer_count);
-#ifdef HAVE_SGEN_GC
                g_print ("Minor GC collections:   %ld\n", mono_stats.minor_gc_count);
-#endif
                g_print ("Major GC collections:   %ld\n", mono_stats.major_gc_count);
-#ifdef HAVE_SGEN_GC
                g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
-#endif
                g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
                if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                        g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
@@ -5611,6 +6139,8 @@ mini_cleanup (MonoDomain *domain)
        cominterop_release_all_rcws ();
 #endif
 
+       mono_runtime_shutdown ();
+
 #ifndef MONO_CROSS_COMPILE     
        /* 
         * mono_runtime_cleanup() and mono_domain_finalize () need to
@@ -5639,7 +6169,8 @@ mini_cleanup (MonoDomain *domain)
        mono_debugger_cleanup ();
 
 #ifdef ENABLE_LLVM
-       mono_llvm_cleanup ();
+       if (mono_use_llvm)
+               mono_llvm_cleanup ();
 #endif
 
        mono_trampolines_cleanup ();
@@ -5650,6 +6181,7 @@ mini_cleanup (MonoDomain *domain)
                mono_code_manager_destroy (global_codeman);
        g_hash_table_destroy (jit_icall_name_hash);
        g_free (emul_opcode_map);
+       g_free (emul_opcode_opcodes);
 
        mono_arch_cleanup ();
 
@@ -5693,9 +6225,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
@@ -5753,7 +6285,22 @@ 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);
 }
+
+void
+mono_cfg_add_try_hole (MonoCompile *cfg, MonoExceptionClause *clause, guint8 *start, MonoBasicBlock *bb)
+{
+       TryBlockHole *hole = mono_mempool_alloc (cfg->mempool, sizeof (TryBlockHole));
+       hole->clause = clause;
+       hole->start_offset = start - cfg->native_code;
+       hole->basic_block = bb;
+
+       cfg->try_block_holes = g_slist_append_mempool (cfg->mempool, cfg->try_block_holes, hole);
+}
+
+#endif