2010-01-04 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / mini / mini.c
index 4bf6f6ce471e49888dfcb6bc7d115b52f0d14a2a..8f7772f061c59122749d858f932f804c045f139d 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>
@@ -65,6 +63,7 @@
 
 #include "debug-mini.h"
 #include "mini-gc.h"
+#include "debugger-agent.h"
 
 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex);
 
@@ -75,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;
@@ -111,6 +111,22 @@ static int mini_verbose = 0;
 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;
@@ -145,17 +161,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 {
@@ -247,9 +259,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;
@@ -266,9 +279,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);
@@ -482,8 +495,14 @@ mono_find_block_region_notry (MonoCompile *cfg, int offset)
        return -1;
 }
 
-MonoInst *
-mono_find_spvar_for_region (MonoCompile *cfg, int region)
+/*
+ * 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);
@@ -497,13 +516,15 @@ mono_find_spvar_for_region (MonoCompile *cfg, int region)
                region = mono_find_block_region_notry (cfg, header->clauses [clause_index].try_offset);
        }
 
-       return g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
+       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
@@ -628,7 +649,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:
@@ -739,6 +762,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;
@@ -983,7 +1018,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);
@@ -1135,7 +1169,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
 
@@ -1263,6 +1297,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)
 {
@@ -1271,6 +1322,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
@@ -1441,6 +1493,9 @@ 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;
                }
 
                t = mono_type_get_underlying_type (inst->inst_vtype);
@@ -1614,8 +1669,10 @@ mono_allocate_stack_slots_full2 (MonoCompile *cfg, gboolean backward, guint32 *s
                         * 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;
@@ -1711,6 +1768,9 @@ 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;
                }
 
                t = mono_type_get_underlying_type (inst->inst_vtype);
@@ -1830,7 +1890,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.
@@ -2181,6 +2242,16 @@ 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)
@@ -2477,6 +2548,7 @@ mono_patch_info_hash (gconstpointer data)
        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);
@@ -2521,7 +2593,6 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
 
                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;
@@ -2539,7 +2610,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:
@@ -2755,6 +2830,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 ();
        }
@@ -2762,6 +2854,15 @@ 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;
+}
+
 static void
 mono_compile_create_vars (MonoCompile *cfg)
 {
@@ -2927,6 +3028,93 @@ mono_postprocess_patches (MonoCompile *cfg)
        }
 }
 
+static void
+mono_save_seq_point_info (MonoCompile *cfg)
+{
+       MonoBasicBlock *bb, *in_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 */
+                               /* 
+                                * FIXME: What if the prev bb doesn't have a seq point, but
+                                * one of its predecessors has ?
+                                */
+                               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));
+                               }
+                       }
+
+                       last = ins;
+               }
+       }
+
+       for (i = 0; i < cfg->seq_points->len; ++i) {
+               SeqPoint *sp = &info->seq_points [i];
+               GSList *l;
+               int j;
+
+               sp->next_len = g_slist_length (next [i]);
+               sp->next = g_new (int, sp->next_len);
+               j = 0;
+               for (l = next [i]; l; l = l->next)
+                       sp->next [j ++] = GPOINTER_TO_UINT (l->data);
+               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)
 {
@@ -3062,7 +3250,7 @@ if (valgrind_register){
        } else {
                mono_domain_code_commit (cfg->domain, cfg->native_code, cfg->code_size, cfg->code_len);
        }
-       mono_profiler_code_buffer_new (code, cfg->code_len, MONO_PROFILER_CODE_BUFFER_METHOD, cfg->method);
+       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);
 
@@ -3137,9 +3325,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        try_llvm = FALSE;
 #endif
 
-       if (compile_aot)
-               try_llvm = FALSE;
-
  restart_compile:
        if (try_generic_shared) {
                MonoMethod *declaring_method;
@@ -3177,22 +3362,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;
        }
 
-       /* No way to obtain the location info for 'this' */
-       if (try_generic_shared) {
-               cfg->exception_message = g_strdup ("gshared");
+       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 (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;
@@ -3203,6 +3469,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;
@@ -3237,23 +3505,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                cfg->opt |= MONO_OPT_ABCREM;
        }
 
-       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);
-               if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
-                       mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
-               return cfg;
-       }
-
        if (getenv ("MONO_VERBOSE_METHOD")) {
                if (strcmp (cfg->method->name, getenv ("MONO_VERBOSE_METHOD")) == 0)
                        cfg->verbose_level = 4;
@@ -3337,6 +3588,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
         */
@@ -3362,8 +3617,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;
        }
@@ -3395,6 +3648,22 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                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);*/
 
        if (!COMPILE_LLVM (cfg))
@@ -3421,6 +3690,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) {
@@ -3441,6 +3712,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)
@@ -3469,11 +3742,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
@@ -3482,7 +3760,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
@@ -3568,7 +3846,8 @@ 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
        if (!COMPILE_LLVM (cfg))
                mono_decompose_vtype_opts (cfg);
@@ -3596,12 +3875,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);
 
@@ -3636,8 +3911,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
     //print_dfn (cfg);
        
        /* variables are allocated after decompose, since decompose could create temps */
-       if (!cfg->globalra && !COMPILE_LLVM (cfg))
+       if (!cfg->globalra && !COMPILE_LLVM (cfg)) {
                mono_arch_allocate_vars (cfg);
+               if (cfg->exception_type)
+                       return cfg;
+       }
 
        {
                MonoBasicBlock *bb;
@@ -3697,13 +3975,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        if (COMPILE_LLVM (cfg)) {
 #ifdef ENABLE_LLVM
                char *nm;
-               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 without using LLVM", MONO_COUNTER_JIT | MONO_COUNTER_INT, &methods_without_llvm);
-                       inited = TRUE;
-               }
 
                /* The IR has to be in SSA form for LLVM */
                if (!(cfg->comp_done & MONO_COMP_SSA)) {
@@ -3711,19 +3982,17 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                        cfg->disable_llvm = TRUE;
                }
 
-               /* FIXME: */
-               if (cfg->method->dynamic) {
-                       cfg->exception_message = g_strdup ("dynamic.");
-                       cfg->disable_llvm = TRUE;
-               }
-
                if (cfg->flags & MONO_CFG_HAS_ARRAY_ACCESS)
                        mono_decompose_array_access_opts (cfg);
 
                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 >= 2) {
+                       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);
@@ -3736,7 +4005,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
                InterlockedIncrement (&methods_with_llvm);
 
-               if (cfg->verbose_level > 0) {
+               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, 
@@ -3768,15 +4037,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                                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;
@@ -3855,17 +4115,26 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                                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 (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;
+                       }
                }
        }
 
@@ -3899,6 +4168,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        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);
@@ -3929,8 +4200,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;
 }
@@ -3992,12 +4261,13 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 {
        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);
@@ -4006,6 +4276,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;
                }
        }
@@ -4020,7 +4291,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);
@@ -4155,6 +4426,10 @@ 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);
+
                return NULL;
        }
 
@@ -4186,6 +4461,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) {
@@ -4214,6 +4493,10 @@ 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)
+               mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
+
        mono_runtime_class_init (vtable);
        return code;
 }
@@ -4428,19 +4711,25 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        mono_domain_unlock (domain);            
 
        if (!info) {
-               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;
+               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;
+                       }
                }
 
                info = g_new0 (RuntimeInvokeInfo, 1);
 
                invoke = mono_marshal_get_runtime_invoke (method, FALSE);
-               info->vtable = mono_class_vtable (domain, method->klass);
+               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) &&
@@ -4616,7 +4905,7 @@ SIG_HANDLER_SIGNATURE (mono_sigfpe_signal_handler)
 {
        MonoException *exc = NULL;
        MonoJitInfo *ji;
-#ifndef MONO_ARCH_USE_SIGACTION
+#if !(defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32))
        void *info = NULL;
 #endif
        GET_CONTEXT;
@@ -4664,6 +4953,16 @@ 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
+
        /* The thread might no be registered with the runtime */
        if (!mono_domain_get () || !jit_tls) {
                if (mono_chain_signal (SIG_HANDLER_PARAMS))
@@ -4752,7 +5051,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;
@@ -4801,9 +5100,15 @@ mini_parse_debug_options (void)
                        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 {
                        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'\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'\n");
                        exit (1);
                }
        }
@@ -4865,9 +5170,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->static_rgctx_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;
 }
@@ -4921,9 +5227,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);
-       g_hash_table_destroy (info->static_rgctx_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;
@@ -4980,11 +5292,19 @@ mini_init (const char *filename, const char *runtime_version)
 
        mini_gc_init ();
 
+       if (getenv ("MONO_DEBUG") != NULL)
+               mini_parse_debug_options ();
+
        if (getenv ("MONO_XDEBUG")) {
-               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
@@ -4996,9 +5316,6 @@ mini_init (const char *filename, const char *runtime_version)
        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 ();
@@ -5007,6 +5324,8 @@ 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
@@ -5030,9 +5349,12 @@ 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 ENABLE_LLVM
-       /* The runtime currently only uses this for filling out vtables */
-       mono_install_trampoline (mono_create_llvm_vcall_trampoline);
+#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
@@ -5067,11 +5389,15 @@ 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);
-               mono_install_imt_trampoline (mini_get_imt_trampoline ());
-#ifndef ENABLE_LLVM
-               /* LLVM needs a per-method vtable trampoline */
-               mono_install_vtable_trampoline (mini_get_vtable_trampoline ());
-#endif
+               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
 
@@ -5273,6 +5599,7 @@ 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_get_native_calli_wrapper, "mono_get_native_calli_wrapper", "ptr ptr ptr ptr", FALSE);
 #endif
 
        mono_generic_sharing_init ();
@@ -5415,12 +5742,12 @@ mini_cleanup (MonoDomain *domain)
        /* This accesses metadata so needs to be called before runtime shutdown */
        print_jit_stats ();
 
+       mono_profiler_shutdown ();
+
 #ifndef MONO_CROSS_COMPILE
        mono_runtime_cleanup (domain);
 #endif
 
-       mono_profiler_shutdown ();
-
        mono_icall_cleanup ();
 
        mono_runtime_cleanup_handlers ();
@@ -5468,6 +5795,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:
  *
@@ -5478,9 +5811,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